1 import time 2 3 # time模块有提供时间相关函数 4 def do_something(): 5 print("do_something") 6 time.sleep(0.5) # 让程序中止0.5秒模拟其它操做耗时 7 8 start = time.time() 9 do_something() 10 print(time.time() - start) 11 #result: 12 # do_something 13 # 0.5000283718109131
问题:上述代码能够完成这个功能,但以后会发现,若是咱们要统计其它函数,就必须在每一个函数先后加入相应代码python
1 import time 2 3 def execute_time(func): 4 def inner(): 5 start = time.time() 6 func() 7 print(time.time() - start) 8 9 return inner 10 11 # time模块有提供时间相关函数 12 def do_something(): 13 print("do_something") 14 time.sleep(0.5) # 让程序中止0.5秒模拟其它操做耗时 15 16 do_something = execute_time(do_something) 17 do_something() 18 #result: 19 # do_something 20 # 0.5000283718109131
从上述代码能够看到,使用了另外一个函数execute_time()给咱们要统计耗时的函数进行了包装,这时,这个execute_time()函数就叫作装饰器函数,而咱们要统计的那个函数也就是do_something()函数就是被装饰的函数.问题:函数执行的时候其实是调用的execute_time()函数中的inner()函数,这种方法虽然解决了原始版本的问题,可是当咱们要统计的函数拥有返回值的时候,这时候咱们获取不到返回值.app
import time def execute_time(func): def inner(do): start = time.time() result = func(do) print(time.time() - start) return result return inner # time模块有提供时间相关函数 def do_something(do): print("do_something", do) time.sleep(0.5) # 让程序中止0.5秒模拟其它操做耗时 return 'do_something over' do_something = execute_time(do_something) print(do_something('say hello')) # result: # do_something say hello # 0.5000283718109131 # do_something over
为了解决装饰器版本1的问题,我在inner()函数里面加了个返回值.问题:当被装饰函数的参数个数与inner()参数个数不一样时,这个装饰器就不适用了函数
1 import time 2 3 def execute_time(func): 4 def inner(*args, **kwargs): 5 start = time.time() 6 result = func(*args, **kwargs) 7 print(time.time() - start) 8 return result 9 10 return inner 11 12 # time模块有提供时间相关函数 13 def do_something(do1,do2): 14 print("do_something", do1,do2) 15 time.sleep(0.5) # 让程序中止0.5秒模拟其它操做耗时 16 return 'do_something over' 17 18 do_something = execute_time(do_something) 19 print(do_something('say hello1','say hello2')) 20 # result: 21 # do_something say hello1 say hello2 22 # 0.5000283718109131 23 # do_something over
在第七天内容中有个知识点是动态参数,恰好能够解决这个问题spa
1 import time 2 3 def execute_time(func): 4 def inner(*args, **kwargs): 5 start = time.time() 6 result = func(*args, **kwargs) 7 print(time.time() - start) 8 return result 9 10 return inner 11 12 @execute_time 13 def do_something(do1,do2): 14 print("do_something", do1,do2) 15 time.sleep(0.5) # 让程序中止0.5秒模拟其它操做耗时 16 return 'do_something over' 17 18 # do_something = execute_time(do_something) 19 print(do_something('say hello1','say hello2')) 20 # result: 21 # do_something say hello1 say hello2 22 # 0.5000283718109131 23 # do_something over
对于装饰器,python内部给咱们提供了语法糖支持.在须要被装饰的函数名上部使用[@装饰器函数名称]便可,简化上述代码18行code
1 def func(): 2 print('执行中') 3 print(func.__name__) 4 5 func() 6 # result: 7 # 执行中 8 # func
常规函数能够经过函数的__name__属性可拿到当前函数名称orm
1 def wrapper(func): 2 def inner(): 3 print('执行前') 4 result = func() 5 print('执行后') 6 return result 7 return inner; 8 @wrapper 9 def func(): 10 print('执行中') 11 print(func.__name__) 12 13 func() 14 # result: 15 # 执行前 16 # 执行中 17 # inner 18 # 执行后
问题:经过执行结果会发现,结果中想获取的函数名是func,而实际结果是inner.缘由是@wrapper进行包装至关于执行一个操做:func=wrapper(func)=innerblog
使用functools模块form
1 from functools import wraps 2 3 def wrapper(func): 4 @wraps(func) 5 def inner(): 6 print('执行前') 7 result = func() 8 print('执行后') 9 return result 10 11 return inner; 12 13 @wrapper 14 def func(): 15 print('执行中') 16 print(func.__name__) 17 18 func() 19 # result: 20 # 执行前 21 # 执行中 22 # func 23 # 执行后
导入functools模块后经过第4行操做,会发现执行的函数即便被包装但仍是能获取到它自己的属性class
1 def wrapper(func): 2 def inner(): 3 print('执行前') 4 result = func() 5 print('执行后') 6 return result 7 8 return inner; 9 10 @wrapper 11 def func_1(): 12 print('执行中') 13 14 @wrapper 15 def func_2(): 16 print('执行中') 17 18 @wrapper 19 def func_3(): 20 print('执行中') 21 ... 22 @wrapper 23 def func_n(): 24 print('执行中')
问题:经过上述代码会发现,有不少函数都用了同一个装饰器,若是有一天要取消这些函数上的装饰,就必须对每个函数进行修改import
定义一个全局变量flag,并给本来装饰器外部再加一层函数用来接收参数,inner()函数内部经过外部参数flag判断被装饰函数的执行与否,修改flag便可控制装饰器的执行结果,以下:
1 from functools import wraps 2 flag = True 3 4 def wrapper_out(flag): 5 def wrapper(func): 6 @wraps(func) 7 def inner(): 8 if (flag): 9 print('{}执行前'.format(func.__name__)) 10 result = func() 11 print('{}执行后'.format(func.__name__)) 12 else: 13 result = func() 14 return result 15 16 return inner 17 18 return wrapper 19 20 @wrapper_out(flag) 21 def func_1(): 22 print('{}执行中'.format(func_1.__name__)) 23 24 @wrapper_out(flag) 25 def func_2(): 26 print('{}执行中'.format(func_2.__name__)) 27 28 @wrapper_out(flag) 29 def func_3(): 30 print('{}执行中'.format(func_3.__name__)) 31 32 ... 33 34 @wrapper_out(flag) 35 def func_n(): 36 print('{}执行中'.format(func_n.__name__)) 37 38 func_1() 39 func_2() 40 func_3() 41 func_n() 42 43 #result: 44 # func_1执行前 45 # func_1执行中 46 # func_1执行后 47 # func_2执行前 48 # func_2执行中 49 # func_2执行后 50 # func_3执行前 51 # func_3执行中 52 # func_3执行后 53 # func_n执行前 54 # func_n执行中 55 # func_n执行后
from functools import wraps flag = False def wrapper_out(flag): def wrapper(func): @wraps(func) def inner(): if (flag): print('{}执行前'.format(func.__name__)) result = func() print('{}执行后'.format(func.__name__)) else: result = func() return result return inner return wrapper @wrapper_out(flag) def func_1(): print('{}执行中'.format(func_1.__name__)) @wrapper_out(flag) def func_2(): print('{}执行中'.format(func_2.__name__)) @wrapper_out(flag) def func_3(): print('{}执行中'.format(func_3.__name__)) ... @wrapper_out(flag) def func_n(): print('{}执行中'.format(func_n.__name__)) func_1() func_2() func_3() func_n() #result: # func_1执行中 # func_2执行中 # func_3执行中 # func_n执行中
1 def wrapper1(func): 2 def inner(): 3 print('wrapper1 ,before func') 4 func() 5 print('wrapper1 ,after func') 6 7 return inner 8 9 def wrapper2(func): 10 def inner(): 11 print('wrapper2 ,before func') 12 func() 13 print('wrapper2 ,after func') 14 15 return inner 16 17 @wrapper1 18 @wrapper2 19 def f(): 20 print('in f') 21 22 f() 23 # result: 24 # wrapper1 ,before func 25 # wrapper2 ,before func 26 # in f 27 # wrapper2 ,after func 28 # wrapper1 ,after func
从上图能够看到,从1-9步是装饰器的装载过程,10-18步是执行过程.结论:多个装饰器装饰同一个函数时,装载顺序是从下到上,但执行顺序倒是从上到下,能够理解为建立了一个装饰器栈(先进后出)