python装饰器

【摘要】

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象.;常用场景比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的代码并重用。本章主要讲解几种装饰器的写法,包括被装饰函数是否含参数、装饰器是否带参数、类装饰器。

 

  • 普通装饰器不带参数,被装饰函数不带参数
  1. def dec1(func):  
  2.     print('========2===========')  
  3.   
  4.     def inner():  
  5.         print('========3===========')  
  6.         func()  
  7.   
  8.     return inner  
  9.  
  10.  
  11.  
  12. @dec1  只要Python解释器解释到这一行时,就会自动执行装饰,而不是等到要执行f1()函数才开始装饰 func1=dec1(func1)  
  13. def func1():  
  14.     print('========1===========')  
  15.   
  16.   
  17. func1()  
  18. 输出如下:  
  19. # ========2===========  
  20. # ========3===========  
  21. # ========1===========  

 

  • 普通装饰器不带参数,被装饰函数带参数
  1. 由于被装饰后的函数返回的是装饰器的内函数,因此,只需要往装饰器的内函数加上可变参数*args和关键字参数**kwargs  
  2. def dec2(func):  
  3.     print('========2===========')  
  4.   
  5.     def inner(*args, **kwargs):  
  6.         print('========3===========')  
  7.         func(*args, **kwargs)  
  8.   
  9.     return inner  
  10.  
  11.  
  12. @dec2   # @dec2等同于func2 = dec2(func2)('hello','world')  
  13. def func2(a, b):  
  14.     print('========1===========')  
  15.     print(a, b)  
  16.   
  17.   
  18. func2('hello''world')  
  19. 输出如下:  
  20. # ========2===========  
  21. # ========3===========  
  22. # ========1===========  
  23. # ('hello', 'world')  

 

  • 普通装饰器带参数,被装饰函数也带参数
  1. 外层嵌套一层函数传参,返回一个装饰器,这时就可以通过外层的函数传进参数  
  2. def outer(arg):  
  3.     print arg  
  4.   
  5.     def dec3(func):  
  6.         print('========2===========')  
  7.   
  8.         def inner(*args, **kwargs):  
  9.             print('========3===========')  
  10.             func(*args, **kwargs)  
  11.   
  12.         return inner  
  13.   
  14.     return dec3  
  15.  
  16.  
  17. @outer('带参数装饰器')  等同于func3 = outer('带参数装饰器')(func3)('hello','world')  
  18. def func3(a, b):  
  19.     print('========1===========')  
  20.     print(a, b)  
  21.   
  22.   
  23. func3('hello''world')  
  24. 输出如下:  
  25. 带参数装饰器  
  26. # ========2===========  
  27. # ========3===========  
  28. # ========1===========  
  29. # ('hello', 'world')  

 

  • 类装饰器(类中重写__call__方法)不带参数,被装饰函数也不带参数
  1. class Decorator1(object):  
  2.     def __init__(self, func):  
  3.         self.func = func  
  4.   
  5.     def __call__(self):  
  6.         print '这是不接受参数的类装饰器'  
  7.         self.func()  
  8.  
  9.  
  10. @Decorator1  
  11. def func6():  
  12.     print('========1===========')  
  13.   
  14.   
  15. func6()  相当于执行类中的__call__方法  
  16. 输出如下:  
  17. 这是不接受参数的类装饰器  
  18. # ========1===========  

 

  • 类装饰器不带参数,被装饰函数带参数

类装饰器需要满足两个条件:1)类的实例是可以调用的,可通过实现函数__call__,从而使得类的实例可以被调用;2)需要将被装饰函数传递到类的实例里,可通过定义__init__时将被修饰函数传递进去。

  1. class Decorator2(object):  
  2.     def __init__(self, func):  
  3.         self.func = func  
  4.   
  5.     def __call__(self, *args, **kwargs):  
  6.         print '这是接受参数的类装饰器'  
  7.         self.func(*args, **kwargs)  
  8.  
  9.  
  10. @Decorator2  
  11. def func7(a, b):  
  12.     print('========1===========')  
  13.     print(a, b)  
  14.   
  15.   
  16. func7('hello''world')  
  17. 输出如下:  
  18. 这是接受参数的类装饰器  
  19. # ========1===========  
  20. # ('hello', 'world')  

 

  • 类装饰器带参数,且被装饰对象也带参数
  1. class Decorator3(object):  
  2.     def __init__(self, x, y):  
  3.         self.x = x  
  4.         self.y = y  
  5.   
  6.     def __call__(self, func, *args, **kwargs):  
  7.         print '这是接受参数的类装饰器,而且装饰器也带参数'  
  8.         print(self.x, self.y)  
  9.   
  10.         def wrapper(*args, **kwargs):  
  11.             func(*args, **kwargs)  
  12.   
  13.         return wrapper  
  14.  
  15.  
  16. @Decorator3('d1''d2')  
  17. def func8(a, b):  
  18.     print('========1===========')  
  19.     print(a, b)  
  20.   
  21.   
  22. func8('hello''world')  
  23. 输出如下:  
  24. 这是接受参数的类装饰器,而且装饰器也带参数  
  25. # ('d1', 'd2')  
  26. # ========1===========  
  27. # ('hello', 'world')  

 

  • 使用@functools.wraps的目的

 

  1. def dec4_nowraps(func):  
  2.     print('========2===========')  
  3.   
  4.     def inner():  
  5.         print('========3===========')  
  6.         func()  
  7.   
  8.     return inner  
  9.   
  10.   
  11. def dec5_withwraps(func):  
  12.     print('========2===========')  
  13.  
  14.     @functools.wraps(func)  
  15.     def inner():  
  16.         print('========3===========')  
  17.         func()  
  18.   
  19.     return inner  
  20.  
  21.  
  22. @dec4_nowraps  
  23. def func4():  
  24.     print('========1===========')  
  25.     print ('函数名为{0}'.format(func4.__name__))  
  26.  
  27.  
  28. @dec5_withwraps  
  29. def func5():  
  30.     print('========1===========')  
  31.     print ('函数名为{0}'.format(func5.__name__))  
  32.   
  33. func4()  
  34. 输出如下,函数名为装饰器的内函数名:  
  35. # ========2===========  
  36. # ========3===========  
  37. # ========1===========  
  38. 函数名为inner  
  39.   
  40.   
  41. func5()  
  42. 输出如下,函数名为被装饰的函数名:  
  43. # ========2===========  
  44. # ========3===========  
  45. # ========1===========  
  46. 函数名为func5  
  • 总结

以上便是对装饰器几种写法的介绍,工作中可以根据自身实际情况,灵活运用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿木木爱打代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值