這裏先導入time模塊的概念。app
import time print(time.time()) # 打印距離1970年到如今的秒數 time.sleep(1) # 停留一秒再執行下一句
''' 測試一段代碼執行會通過多長時間 ''' import time def func(): # 被裝飾的函數 time.sleep(0.01) # 因爲一個print語句太少,因此這裏故意設置一個時間間隔,以達到預期效果。 print('今天好熱') def timmer(f): # 裝飾器函數 def inner(): start = time.time() f() # 調用被裝飾的函數 end = time.time() print('時間間隔爲:',end - start) return inner result = timmer(func) result()
上面一段代碼就是一個簡單的裝飾器。ide
一般爲了是代碼更加優美,因而引入語法糖的概念。這裏將對上述第二段代碼進行改進,他們的做用和結果徹底相同。函數
''' 測試一段代碼執行會通過多長時間 ''' import time def timmer(f): # 裝飾器函數 def inner(): start = time.time() f() # 調用被裝飾的函數 end = time.time() print('時間間隔爲:',end - start) return inner @timmer #語法糖-@裝飾器函數 def func(): # 被裝飾的函數 time.sleep(0.01) # 因爲一個print語句太少,因此這裏故意設置一個時間間隔,以達到預期效果。 print('今天好熱') # result = timmer(func) @timeer與此句一個做用相同 func() # 分析一下,此func等價於timmer(func),也就至關於inner。
''' 測試一段代碼執行會通過多長時間 ''' # 新增功能-裝入帶參數函數的裝飾器 import time def timmer(f): # 裝飾器函數 def inner(a): start = time.time() f(a) # 調用被裝飾的函數 end = time.time() print('時間間隔爲:',end - start) return inner @timmer #語法糖-@裝飾器函數 def func(a): # 被裝飾的函數 time.sleep(0.01) # 因爲一個print語句太少,因此這裏故意設置一個時間間隔,以達到預期效果。 print('今天好熱',a) # result = timmer(func) @timeer與此句一個做用相同 func(1) # 分析一下,此func等價於timmer(func),也就至關於inner。
上面一段代碼是裝入一個參數,若是我想在被裝飾函數中加入兩個參數呢?也許你會說,再加入一個變量,那麼三個參數呢?這個時候咱們就要用到前面學過的內容:*args。繼續,若是咱們再加入一個關鍵字參數呢?一樣,咱們要用到**kwargs。下面是代碼:學習
''' 測試一段代碼執行會通過多長時間 ''' # 新增功能-裝入帶參數函數的裝飾器 import time def timmer(f): # 裝飾器函數 def inner(*args,**kwargs): start = time.time() f(*args,**kwargs) # 調用被裝飾的函數 end = time.time() print('時間間隔爲:',end - start) return inner @timmer #語法糖-@裝飾器函數 def func(a,b): # 被裝飾的函數 time.sleep(0.01) # 因爲一個print語句太少,因此這裏故意設置一個時間間隔,以達到預期效果。 print('今天好熱',a,b) # result = timmer(func) @timeer與此句一個做用相同 func(1,b = 3) # 分析一下,此func等價於timmer(func),也就至關於inner。
(1)不想修改函數的調用方式,可是還想在原來的函數先後添加功能。測試
(2)timmer就是一個裝飾器函數,只是對一個函數有一些裝飾做用。spa
對擴展是開放的。code
對修改是封閉的。blog
# 學習._name_和._doc_,在這裏若是不作任何修改,._name_會輸出inner,由於study和inner等價,可是咱們作出如下修改,就會成功輸出study from functools import wraps #導入 def wrapper(func): @wraps(func)# 加上這句 def inner(*args,**kwargs): print('在被裝飾的函數執行前要作的事') ret = func(*args,**kwargs) print('在被裝飾的函數執行後要作的事') return ret return inner @wrapper def study(days): ''' 這是一個註釋 :param days: :return: ''' print('堅持學習%s天'%days) return '加油' # ret = study(10) # print(ret) print(study.__name__)# 輸出 print(study.__doc__)
# 若多個函數同時用一個裝飾器,通常來講就是在函數上面加一個@裝飾器名,可是咱們有不想用它的時候,若是咱們一個一個去刪除它則會很是的麻煩,下面這種方法將會解決這種問題。 import time Flag = False def timmer_out(Flag): def timmer(func): def inner(*args,**kwargs): if Flag: start = time.time() ret = func(*args,**kwargs) end = time.time() print(end - start) return ret else: ret = func(*args, **kwargs) return ret return inner return timmer @timmer_out(Flag) def para_fir(): time.sleep(0.1) print('the first') @timmer_out(Flag) def para_sec(): time.sleep(0.1) print('the second') para_fir() para_sec() # 思想就是在裝飾器外再加上一層,成爲三層裝飾器,經過判斷Flag爲True仍是False,來執行相應的代碼塊
def wrapper1(func): # func-->f def inner1(): print('wrapper1 ,before func') ret = func() print('wrapper1 ,after func') return ret return inner1 def wrapper2(func): # func = inenr1 def inner2(): print('wrapper2 ,before func') ret = func() print('wrapper2 ,after func') return ret return inner2 @wrapper2 # f = wrapper2(f) -> wrapper2(inner1) = inner2 @wrapper1 # f = wrapper1(f) = inner1 def f(): print('in f') return '哈哈哈' print(f()) # f = inner2 # result: # wrapper2 ,before func # wrapper1 ,before func # in f # wrapper1 ,after func # wrapper2 ,after func # 哈哈哈 # 仔細觀察這個結果,首先執行wrapper1,將f傳入wrapper1中,因而wrapper1中的func就是f,最後返回一個inner1。接着再執行wrapper2,可是此時傳入wrapper2中的參數是上一次執行返回過來的inner1,因此wrapper2中的func是inner1,最後返回一個inner2。 # 爲何結果是先有wrapper2,可是其實是先執行wrapper1呢,這是由於裝飾器中的語法糖會找最近的一個被修飾的函數,顯然wrapper1更接近f(),而wrapper2比較遠,因此是先執行wrapper1,再是wrapper2。