Python之路第四篇:Python基础(19)——装饰器

Posted 漫画

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python之路第四篇:Python基础(19)——装饰器相关的知识,希望对你有一定的参考价值。

#普通装饰器
# (@+函数名),需要记住关键两点:
#功能:
#1、自动执行outer函数,并且将其下面的函数名f1当作参数传递
#2、将outer函数的返回值,重新赋值给f1

# #装饰器必备
# ####第一:函数名和执行函数####
# def foo(): #创建函数
# print(\'hello\') #函数体
# foo #表示是函数名,代指整个函数
# foo() #表示执行f00函数
# # 输出:hello

# ####第二:函数被重新定义###
# def foo():
# print("foo1")
#
# foo = lambda : print("foo2") #lambda表达式,无参数
#
# foo() #执行下面的lambda表达式,而不是原来的foo函数,foo函数已经被重新定义





# #同名函数被覆盖
# def f1(): #1
# print(123)
#
# def f1():#2 #4
# print(456) #5
# f1() #3
# #输出: 456


#f1函数作为参数进行传递
# def f1(): #1 创建f1函数 #6执行f1()函数,结果是打印输出123
# print("123") #7
# #没有return,默认返回None
# def f2(xxx): #2 创建f2函数 #4 接收到传递的f1以后,xxx也是代指f1函数的整体,f2(xxx)就相当于f2(f1)
# ret = xxx() #5 xxx()就等于是f1(),f1()就代表去执行f1()这整个函数。
#
# f2(f1) #3 调用f2函数,f1作为参数(f1没有单引号和双引号是一个函数名; f1没有带括号(),代指的是f1函数的整体,f1作为参数传递给xxx


# #装饰器 流程剖析 分解功能1:自动执行outer()函数,并将下面的函数名f1作为参数传递 ()
# # def outer(): #TypeError: outer() takes 0 positional arguments but 1 was given 翻译:outer需要0个参数,但传递了1个参数
# def outer(func): #1在内存中创建outer函数 #3执行outer(f1)函数 #这是装饰器的基本格式,必须带参数,如果没有参数就会报错。
# print(123) #4 执行函数体:打印123
# print(func) #5 执行函数体:打印func参数,输出:<function f1 at 0x0000000000B28620>
# @outer #2 自动执行outer()函数,并将下面的函数名f1作为参数传递。即@outer等价于outer(f1)
# def f1():
# print("F1")


# #装饰器 流程剖析 分解功能2:将outer函数的返回值111,重新赋值给f1
# def outer(func): #1在内存中创建outer函数 #3执行outer(f1)函数 #这是装饰器的基本格式,必须带参数,如果没有参数就会报错。
# return "111" #4 将outer函数的返回值111,重新赋值给f1。
# @outer #2 自动执行outer()函数,并将下面的函数名f1作为参数传递
# def f1():
# print("F1")
# print(f1) #5 原来的f1函数被覆盖,被重新赋值为111.


#问题解析:
#4 (为什么outer函数的返回值111,就重新赋值给了f1,f1并没有调用outer(f1)函数啊?)这个问题纠结了我至少4个小时。感谢绍宁指点。如下:
# @outter 等价于 outter(f1)
# 等价于f1=outter(f1)
# outter函数的返回值是111
# 所以f1就变成了111
# 装饰器就是在把原来的函数包起来加工一下,但是加工后还是叫原来的函数名,用了装饰器后 原来的函数名 等于装饰器函数的返回值
# 参考链接:http://www.cnblogs.com/rollenholt/archive/2012/05/02/2479833.html
# #函数是一个对象,可以赋值给其他对象变量,通过变量可以调用该函数。
# def foo():
# print("test")
# f = foo #注意没有使用圆括号,因为不是在调用函数
# f()
# # # 输出:test
# print(foo.__name__)#通过函数对象_name_属性,可以拿到函数的名字:
# #输出:foo
# print(f.__name__)
# # 输出:foo



#装饰器 流程剖析 将outer函数的返回值,换成其他函数。
#注:解释器解释后f1函数就等于111,这样f1函数就被成功修改了,那以后外部再来调用f1函数的时候就会调用111,那我们就成功的将f1函数换成了111
#我们能把f1换成111,同理,也能换成一个其他函数。
# def outer(func): #1在内存中创建outer函数 #3执行outer(f1)函数 #这是装饰器的基本格式,必须带参数,如果没有参数就会报错。
# # return "111" #4 将outer函数的返回值111,重新赋值给f1。
# def inner(): #4 在内存中创建inner函数 #8 外部调用f1()函数就等于是调用inner函数,f1函数换成了inner函数,即新f1函数。
# print("在执行老的f1函数之前执行命令") #9 在执行老的f1函数之前执行
# func() #10 第2步时,f1函数作为参数传递给了outer函数的func参数,func代指的就是老的f1函数,即装饰的原函数,func加括号,代表执行老的f1()函数
# print("在执行老的f1函数之后执行命令") #11 在执行老的f1函数之后执行
# return inner #5 inner不加括号代指的是整个inner函数,将outer函数的返回值inner函数,重新赋值给f1,f1就代指的是inner函数。
# #inner()加括号是执行inner函数,代表的是return之前先执行inner函数,然后把返回值(默认为None)赋值给f1,把inner函数
# #执行后的返回值赋值给f1,外部程序再调用时得到的是inner的返回值,不是f1的返回值,这样做会破坏f1函数原有的功能
#
# @outer #2 自动执行outer()函数,并将下面的函数名f1作为参数传递
# def f1():
# print("F1")
# # print(f1) #6 原来的f1函数被覆盖,被重新赋值为inner函数。# <function outer.<locals>.inner at 0x00000000030AF1E0>


# #装饰器 流程剖析 返回值
# #注:解释器解释后f1函数就等于111,这样f1函数就被成功修改了,那以后外部再来调用f1函数的时候就会调用111,那我们就成功的将f1函数换成了111
# #我们能把f1换成111,同理,也能换成一个其他函数。
# def outer(func): #1在内存中创建outer函数 #3执行outer(f1)函数 #这是装饰器的基本格式,必须带参数,如果没有参数就会报错。
# # return "111" #4 将outer函数的返回值111,重新赋值给f1。
# def inner(): #4 在内存中创建inner函数 #8 外部调用f1()函数就等于是调用inner函数,f1函数换成了inner函数,即新f1函数。
# print("在执行老的f1函数之前执行命令") #9 在执行老的f1函数之前执行
# # ret = func() #10 第2步时,f1函数作为参数传递给了outer函数的func参数,func代指的就是老的f1函数,即装饰的原函数,func加括号,代表执行老的f1()函数
# r = func() #10 执行func()函数,等于执行原f1()函数,原f1函数有返回值,定义变量r用于接收原f1函数的返回值
# print("在执行老的f1函数之后执行命令") #11 在执行老的f1函数之后执行
# return r #12 r代表原f1函数的返回值,新f1函数执行之后将原f1函数的返回值返回给函数调用者。(函数遇到return就不再向下执行,所以把return放在最下面)
# return inner #5 inner不加括号代指的是整个inner函数,将outer函数的返回值inner函数,重新赋值给f1,f1就代指的是inner函数。
# #inner()加括号是执行inner函数,代表的是return之前先执行inner函数,然后把返回值(默认为None)赋值给f1,把inner函数
# #执行后的返回值赋值给f1,外部程序再调用时得到的是inner的返回值,不是f1的返回值,这样做会破坏f1函数原有的功能
#
# @outer #2 自动执行outer()函数,并将下面的函数名f1作为参数传递
# def f1():
# print("F1")
# return "原f1函数返回值FFFF" #原f1函数有返回值FFFF
# # print(f1) #6 原来的f1函数被覆盖,被重新赋值为inner函数。# <function outer.<locals>.inner at 0x00000000030AF1E0>



# #装饰器 流程剖析 1个参数
# #注:解释器解释后f1函数就等于111,这样f1函数就被成功修改了,那以后外部再来调用f1函数的时候就会调用111,那我们就成功的将f1函数换成了111
# #我们能把f1换成111,同理,也能换成一个其他函数。
# def outer(func): #1在内存中创建outer函数 #3执行outer(f1)函数 #这是装饰器的基本格式,必须带参数,如果没有参数就会报错。
# # return "111" #4 将outer函数的返回值111,重新赋值给f1。
# def inner(a): #4 在内存中创建inner函数 #8 外部调用f1()函数就等于是调用inner函数,f1函数换成了inner函数,即新f1函数。#8.1外部调用新f1函数的实参,首先传递给形参“a”
# print("在执行老的f1函数之前执行命令") #9 在执行老的f1函数之前执行
# # ret = func() #10 第2步时,f1函数作为参数传递给了outer函数的func参数,func代指的就是老的f1函数,即装饰的原函数,func加括号,代表执行老的f1()函数
# r = func(a) #10 执行func()函数,等于执行原f1()函数,原f1函数有返回值,定义变量r用于接收原f1函数的返回值 #10.1将函数调用者传递的参数传递给原f1()函数。
# print("在执行老的f1函数之后执行命令") #11 在执行老的f1函数之后执行
# return r #12 r代表原f1函数的返回值,新f1函数执行之后将原f1函数的返回值返回给函数调用者。(函数遇到return就不再向下执行,所以把return放在最下面)
# return inner #5 inner不加括号代指的是整个inner函数,将outer函数的返回值inner函数,重新赋值给f1,f1就代指的是inner函数。
# #inner()加括号是执行inner函数,代表的是return之前先执行inner函数,然后把返回值(默认为None)赋值给f1,把inner函数
# #执行后的返回值赋值给f1,外部程序再调用时得到的是inner的返回值,不是f1的返回值,这样做会破坏f1函数原有的功能
#
# @outer #2 自动执行outer()函数,并将下面的函数名f1作为参数传递
# def f1(arg): #10.2接收函数调用者传递的参数arf = a
# # print("F1")
# print(arg)
# return "原f1函数返回值FFFF" #原f1函数有返回值FFFF
# # print(f1) #6 原来的f1函数被覆盖,被重新赋值为inner函数。# <function outer.<locals>.inner at 0x00000000030AF1E0>



#注:解释器解释后f1函数就等于111,这样f1函数就被成功修改了,那以后外部再来调用f1函数的时候就会调用111,那我们就成功的将f1函数换成了111
#我们能把f1换成111,同理,也能换成一个其他函数。
# def outer(func): #1在内存中创建outer函数 #3执行outer(f1)函数 #这是装饰器的基本格式,必须带参数,如果没有参数就会报错。
# # return "111" #4 将outer函数的返回值111,重新赋值给f1。
# def inner(a): #4 在内存中创建inner函数 #8 外部调用f1()函数就等于是调用inner函数,f1函数换成了inner函数,即新f1函数。#8.1外部调用新f1函数的实参,首先传递给形参“a”
# print("在执行老的f1函数之前执行命令") #9 在执行老的f1函数之前执行
# # ret = func() #10 第2步时,f1函数作为参数传递给了outer函数的func参数,func代指的就是老的f1函数,即装饰的原函数,func加括号,代表执行老的f1()函数
# r = func(a) #10 执行func()函数,等于执行原f1()函数,原f1函数有返回值,定义变量r用于接收原f1函数的返回值 #10.1将函数调用者传递的参数传递给原f1()函数。
# print("在执行老的f1函数之后执行命令") #11 在执行老的f1函数之后执行
# return r #12 r代表原f1函数的返回值,新f1函数执行之后将原f1函数的返回值返回给函数调用者。(函数遇到return就不再向下执行,所以把return放在最下面)
# return inner #5 inner不加括号代指的是整个inner函数,将outer函数的返回值inner函数,重新赋值给f1,f1就代指的是inner函数。
# #inner()加括号是执行inner函数,代表的是return之前先执行inner函数,然后把返回值(默认为None)赋值给f1,把inner函数
# #执行后的返回值赋值给f1,外部程序再调用时得到的是inner的返回值,不是f1的返回值,这样做会破坏f1函数原有的功能
#
# @outer #2 自动执行outer()函数,并将下面的函数名f1作为参数传递
# def f1(arg): #10.2接收函数调用者传递的参数arf = a
# # print("F1")
# print(arg)
# return "原f1函数返回值FFFF" #原f1函数有返回值FFFF
# # print(f1) #6 原来的f1函数被覆盖,被重新赋值为inner函数。# <function outer.<locals>.inner at 0x00000000030AF1E0>















#装饰器 流程剖析 函数传递多个参数使用万能参数,*args,**kwargs

def outer(func): #创建outer函数;f2函数作为参数传递给outer函数,func代指装饰的原函数,即原f2函数。
def inner(*args,**kwargs): #创建嵌套的inner函数,a,b接收f2函数调用者传递的参数 #*args,**kwargs可以接收任意参数
# pass
print("before:执行原函数之前")
r = func(*args,**kwargs) #执行原函数,接收原函数返回值;a,b将调用者传递的参数传递给原f2函数。#python自动把*args,**kwargs里面的参数传递给原函数 print("after:执行原函数之后") return r #返回原函数返回值 return inner #将inner函数的返回值重新赋值给f2函数,inner函数即为新f2函数。(inner后面无括号)@outerdef f1(): print("F1") return "f1"@outerdef f2(a1,a2): print(a1,a2) return "f2"

以上是关于Python之路第四篇:Python基础(19)——装饰器的主要内容,如果未能解决你的问题,请参考以下文章

Python之路,第四篇:Python入门与基础5

Pthon学习之路 第四篇 Python基础

Python之路第四篇python基础 之基本数据类型之集合

python学习之路基础篇(第四篇)

Python之路PythonThread,第四篇,进程4

Python之路PythonNet,第四篇,网络4