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)