Python学习笔记之装饰器
装饰器简单来说,就是现有的对象,在不修改源代码和调用方式的情况,对现有的对象添加新的功能,比如插入日志,权限校验之类的。
为什么要用装饰器?
1、现在有这么一个对象,我要给这个对象添加一个打印日志的功能
1 def foo(): 2 print("I'm foo function")
2、那么可以这样改
1 def foo(): 2 print("I'm foo function") 3 print("logging")
但是如果有10个对象,是不是要在10处加上打印日志的代码?那如果是50个,100个呢?这样会有大量重复的代码出现
3、那还可以这样改,把foo当作一个参数传给日志功能不就好了么
1 def foo(): 2 print("I'm foo function") 3 4 def logging(func): 5 print("logging") 6 func() 7 8 logging(foo)
这样会有一个情况就是,修改了调用方式,假如这段代码已经在生产环境中运行了,而且有很多地方都引用这段代码,不可能把所有已经引用的地方全都修改了吧
这时候就需要用到装饰器了,不用修改原来对象的代码和调用方式,添加新的功能,还可以避免写重复的代码
函数可以赋值给变量
例如
1 def foo(): 2 print("I'm foo function") 3 4 f = foo 5 f() 6 7 #输出结果 8 I'm foo function
函数名后面有小括号和没有小括号的区别
1 def foo(): 2 print("I'm foo function") 3 4 print(foo) #没有小括号表示函数的内存地址 5 print('---我---是---分---割---线---') 6 print(foo()) #有小括号表示函数的执行结果 7 8 #输出结果 9 <function foo at 0x0000026EE94C8F70> 10 ---我---是---分---割---线--- 11 I'm foo function 12 None
为什么要说这个函数可以赋值和有没有小括号的问题呢,因为下面会用到这个
没有参数的对象进行装饰
1、还是这个例子,为其添加日志功能
1 def foo(): 2 print("I'm foo function")
2、下面看一下两个例子
(1)语法糖的写法
1 def logging(func): #1 2 def deco(): #3 3 print("logging") #6 4 func() #7 5 return deco #4 6 7 @logging #2 8 def foo(): 9 print("I'm foo function") #8 10 11 foo() #5 12 13 #输出结果 14 logging 15 I'm foo function
(注:#1 #2 #3 ....#8 其表示的意思是在调试模式下的执行顺序)
(2)重新赋值的写法
1 def logging(func): #1 2 def deco(): #4 3 print("logging") #7 4 func() #8 5 return deco #5 6 7 def foo(): #2 8 print("I'm foo function") #9 9 10 foo=logging(foo) #3 11 foo() #6 12 13 #输出结果 14 logging 15 I'm foo function
(注:#1 #2 #3 ....#9 其表示的意思是在调试模式下的执行顺序)
这两个例子是等价关系,语法糖@logging的写法,相当于隐式的做了foo=logging(foo)
logging(foo)返回的是deco这个函数的内存地址,被重新赋值给了foo这个函数名,所以现在foo=deco
当执行foo()的时候,其实就是deco()
需要注意的是foo和foo()这两个的区别,foo是表示一个内存地址,而foo()表示的是执行结果
有参数的对象进行装饰
1 def logging(func): 2 def deco(*args, **kwargs): # *args表示可以接收任意个位置参数,**kwargs表示可以接收任意个关键字参数, 位置参数*args要放在关键字参数**kwargs的前面 3 print("logging") 4 func(*args, **kwargs) 5 return deco 6 7 @logging 8 def foo(): 9 print("My name is foo function") 10 11 @logging 12 def bar(a, b): 13 print("My name is %s %s"%(a, b)) 14 15 @logging 16 def ten(x, y): 17 print("My name is %s %s"%(x, y)) 18 19 20 foo('foo') 21 print('---我---是---分---割---线---') 22 bar('bar', 'function') 23 print('---我---是---分---割---线---') 24 ten('ten', y='function') 25 26 #输出结果 27 logging 28 My name is foo function 29 ---我---是---分---割---线--- 30 logging 31 My name is bar function 32 ---我---是---分---割---线--- 33 logging 34 My name is ten function
可适用于不带参数的对象、带参数的对象,以及关键字参数的对象的装饰
当然还有一些更高级的用法,比如装饰器也带参数的
可参考以下两个文章:
https://www.cnblogs.com/arvin-feng/p/11108799.html
https://www.liaoxuefeng.com/wiki/1016959663602400/1017451662295584
若以上内容表述有误,欢迎各位大神指导一下。