《Python语言程序设计》 —3.5.5 装饰器

举报
华章计算机 发表于 2019/11/18 21:15:46 2019/11/18
【摘要】 本节书摘来自华章计算机《Python语言程序设计》一书中第3章,第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只能用于装饰没有参数的函数。


【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。