装饰器的完整实现及原理

匿名 (未验证) 提交于 2019-12-02 22:11:45

1、简单装饰器

print(foo.__closure__[0].cell_contents)<function foo at 0x000001F2C7465620>

装饰之前:

  • <function foo at 0x000002569AAB5620>
  • foo
  • this is foo

装饰之后:

  • <function check_result.<locals>.wrapper at 0x00000250E11F56A8>
  • wrapper
  • this is wrapper
 1 '''  2 简单装饰器:  3     实现装饰后函数的功能是如果x和y相乘为负数,则返回0  4 '''  5   6 def check_result(func):  7     '''hahah'''  8     def wrapper(*args, **kwargs):  9         '''this is wrapper''' 10         result = func(*args, **kwargs) 11  12         if result < 0: 13             return 0 14         else: 15             return result 16     return wrapper 17  18  19 @check_result 20 def foo(x, y): 21     '''this is foo''' 22     return x * y 23  24  25  26  27 # 装饰过程拆解 28 # wrapper = check_result(foo) 29 # foo = wrapper

2、多层装饰器

 1 '''  2 多层装饰器  3 '''  4   5 def deco1(func):  6     def wrapper1(*args, **kwargs):  7         '''this is wrapper1'''  8         print('start 1')  9         result = func(*args, **kwargs) 10         print('end   1') 11         return result 12     return wrapper1 13  14  15 def deco2(func): 16     def wrapper2(*args, **kwargs): 17         '''this is wrapper2''' 18         print('start 2') 19         result = func(*args, **kwargs) 20         print('end   2') 21         return result 22     return wrapper2 23  24  25 def deco3(func): 26     def wrapper3(*args, **kwargs): 27         '''this is wrapper3''' 28         print('start 3') 29         result = func(*args, **kwargs) 30         print('end   3') 31         return result 32     return wrapper3 33  34  35 @deco1 36 @deco2 37 @deco3 38 def foo(x, y): 39     '''this is foo''' 40     return x * y 41  42 print(foo(8, 9)) 43 ''' 44 输出结果: 45     start 1 46     start 2 47     start 3 48     end   3 49     end   2 50     end   1 51     72 52 ''' 53  54  55 ''' 56 装饰的过程: 57     wrapper3 = deco3(foo) 58     wrapper2 = deco2(wrapper3) 59     wrapper1 = deco1(wrapper2) 60     foo = wrapper1 61  62  63 执行的过程:正好和装饰的过程相反。 64         foo(8, 9)--->wrapper1(8, 9)--->deco1(wrapper2)(8, 9)---> 65                                                                 | 66                                                                 v 67         deco1( deco2( deco3(foo) ) )(8, 9)<---deco1( deco2(wrapper3) )(8, 9) 68         类比穿衣服,穿(装饰)的时候从里往外一层套一层,脱(执行)的时候从外到里一层一层脱。 69 '''

3、带参装饰器

说明:传入函数执行的次数,统计执行完成的时间。

实现方法:使用工厂模式,定义一个工厂函数,它本身不是装饰器,但是返回值是一个装饰器,是用来"生产"装饰器的。如下所示:

 1 '''  2 带参装饰器  3 '''  4   5 import time  6   7 def timer(count):  8     def deco(func):  9         def wrapper(*args, **kwargs): 10             '''this is wrapper''' 11             t1 = time.time() 12             for i in range(count): 13                 result = func(*args, **kwargs) 14             t2 = time.time() 15             print(t2 - t1) 16             return result 17         return wrapper 18     return deco 19  20  21 @timer(10000000)      # 获取foo执行10000000次的时间 22 def foo(x, y): 23     '''this is foo''' 24     return x * y

4、类装饰器

说明:想要明白类装饰器的原理,我们先要了解一下__call__这个方法。这个方法是python中所有能被调用的对象具有的内置方法,比如类,函数。调用类的过程就是得到一个类的实例的过程,如果要做类装饰器我们得让该类的实例可以被调用。装饰器的本质也是一个函数被调用执行的过程。先看下面一段代码:

 1 class A:  2     pass  3   4   5 def foo(x, y):  6     return x, y  7   8   9 print(A.__call__) 10 print(foo.__call__) 11  12 print(foo.__call__(3, 5))   # 打印结果  15 13 print(foo(3, 5))            # 打印结果  15

callable()

'__call__' of type object at 0x000002CE9522BF48>

根据这个特性,我们设计我们的类装饰器:

 1 '''  2 类装饰器  3 '''  4   5 class Deco:  6     '''this is Deco'''  7     def __init__(self, func):  8         self.func = func  9  10     def __call__(self, *args, **kwargs): 11         result = self.func(*args, **kwargs) 12         if result < 0: 13             return 0 14         else: 15             return result 16  17  18 @Deco                 # 装饰后若结果为负数则返回0 19 def foo(x, y): 20     '''this is foo''' 21     return x * y 22  23 ''' 24 装饰过程如下: 25     这个时候foo引用了Deco的一个实例,执行foo()也就是实例调用__call__方法的过程。 26 ''' 27 foo = Deco(foo)

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!