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步是執行過程.結論:多個裝飾器裝飾同一個函數時,裝載順序是從下到上,但執行順序倒是從上到下,能夠理解爲建立了一個裝飾器棧(先進後出)