《Python语言程序设计》 —3.5.5 装饰器
3.5.5 装饰器
利用装饰器,可以在不修改已有函数的情况下向已有函数中注入代码,使其具备新的功能。一个装饰器可以为多个函数注入代码,一个函数也可以注入多个装饰器的代码。下面通过具体例子说明装饰器的使用方法,参见代码清单3-32。
代码清单3-32 装饰器示例1
1 def deco1(func): #定义函数deco1
2 def inner1(*args, **kwargs): #定义函数inner1
3 print('deco1 begin')
4 func(*args, **kwargs)
5 print('deco1 end')
6 return inner1 #返回函数inner1的引用
7 def deco2(func): #定义函数deco2
8 def inner2(*args, **kwargs): #定义函数inner2
9 print('deco2 begin')
10 func(*args, **kwargs)
11 print('deco2 end')
12 return inner2 #返回函数inner2的引用
13 @deco1
14 def f1(a,b): #定义函数f1
15 print('a+b=',a+b)
16 @deco1
17 @deco2
18 def f2(a,b,c): #定义函数f2
19 print('a+b+c=',a+b+c)
20 if __name__=='__main__': #当脚本文件独立执行时,则调用f1函数和f2函数
21 f1(3,5) #调用f1函数
22 f2(1,3,5) #调用f2函数
程序执行完毕后,将在屏幕上输出如下结果:
deco1 begin
a+b= 8
deco1 end
deco1 begin
deco2 begin
a+b+c= 9
deco2 end
deco1 end
下面对代码清单3-32进行分析:
第1~6行代码定义了一个装饰器,第7~12行代码定义了另一个装饰器,可见装饰器实际上就是前面所学习的闭包。
在装饰器外层函数的形参列表中只有一个形参func(形参名可以自己设置,满足标识符命名规则即可),接收要装饰的函数,在内层函数中直接调用func即表示执行所装饰的函数中的代码。
将装饰器内层函数的形参列表写为“*args,**kwargs”,表示要装饰的函数可以具有任意形式的形参列表;对应地,调用要装饰的函数时也要将实参列表写为“*args,**kwargs”。
在要装饰的函数前面写上“@装饰器名”,即可将装饰器中的代码注入该函数中。例如,对于第13~15行代码,会将deco1中的代码注入f1函数中,deco1中的func(*arg,**kwargs)即对应f1函数的调用。因此,在第21行调用f1函数时,会先输出deco1 begin,再执行f1函数中的代码输出a+b= 8,最后输出deco1 end。
当一个函数前面有多个“@装饰器名”时,将按照从后至前的顺序依次装饰。例如,对于第16~19行代码,先使用deco2装饰f2函数,即在f2函数的代码前注入print('deco2 begin'),在f2函数的代码后注入print('deco2 end');然后在前面装饰的基础上使用deco1装饰,即在已装饰代码前注入print('deco1 begin'),在已装饰代码后注入print('deco1 end')。f2函数装饰后,其实际执行的代码如下所示:
print('deco1 begin')
print('deco2 begin')
print('a+b+c=',a+b+c)
print('deco2 end')
print('deco1 end')
提示 利用装饰器可以将日志处理、执行时间计算等较为通用的代码注入不同的函数中,从而使得代码更加简洁。
如果要注入函数的形参列表形式固定,则在定义装饰器时也可以不使用“*args,**kwargs”这种通用形式,如代码清单3-33所示。
代码清单3-33 装饰器示例2
1 def deco1(func): #定义函数deco1
2 def inner1(x,y): #定义函数inner1
3 print('deco1 begin')
4 func(x,y)
5 print('deco1 end')
6 return inner1 #返回函数inner1的引用
7 def deco2(func): #定义函数deco2
8 def inner2(): #定义函数inner2
9 print('deco2 begin')
10 func()
11 print('deco2 end')
12 return inner2 #返回函数inner2的引用
13 @deco1
14 def f1(a,b): #定义函数f1
15 print('a+b=',a+b)
16 @deco2
17 def f2(): #定义函数f2
18 print('f2 is called')
19 if __name__=='__main__': #当脚本文件独立执行时,则调用f1函数和f2函数
20 f1(3,5) #调用f1函数
21 f2() #调用f2函数
程序执行完毕后,将在屏幕上输出如下结果:
deco1 begin
a+b= 8
deco1 end
deco2 begin
f2 is called
deco2 end
此时,deco1只能用于装饰带两个参数的函数,而deco2只能用于装饰没有参数的函数。
- 点赞
- 收藏
- 关注作者
评论(0)