裝飾器這個名詞一聽就充滿了高級感,並且不少狀況下確實也不經常使用。但裝飾器有裝飾器的好處,至少了解這個對裝逼仍是很有益處的。網上有不少關於裝飾器的解說,但一般都太過「按部就班」,有的還會講一些「閉包」之類的概念,像我這種腦子不太好使的常常就是前讀後忘……因此我想本身來寫一個很是通俗易懂的解說。閉包
我的最先真正接觸裝飾器是在Kaggle上看別人使用numba加速,函數前一行短短的 @jit 讓你的代碼快到飛起,看起來也很簡潔。那究竟裝飾器是什麼,它又能幹嗎呢?app
P1 裝飾器的做用函數
裝飾器的做用是對多種函數執行一個通用操做。重點是多種和通用。舉個栗子來講,我寫了一個計算執行時長的裝飾器,那麼我能夠把它安在函數A上,也能夠把它安在函數B上,甚至安在任何函數上,由於裝飾器執行的是一個通用操做,與我把它安在哪一個函數上基本無關。注意,這裏咱們說「多種函數」而不是「任意函數」,由於有些裝飾器有特殊用途,並不能在任意函數身上通用。spa
P2 裝飾器的本體code
咱們來看一下裝飾器的結構:blog
def 裝飾器(函數模板): 騷操做 + 函數模板 (稱爲wrapper) return wrapper
因此裝飾器的本質仍是一個函數,這也就是爲何咱們說裝飾器的做用是執行一個操做,只不過和那些普通平凡的函數都不一樣的是,裝飾器的操做是通用的。string
那麼問題又來了,這個」wrapper「又是什麼鬼?wrapper說白了就是一系列騷操做和函數模板的集合,裝飾器函數返回的就是wrapper,也就是說它返回了函數的return和你所定義的騷操做。it
至於函數模板,它不是任何一個特定的函數,它只是一個泛指。咱們能夠來看一下wrapper的結構,這裏我寫的是個最通用的函數模板(經過*args和**kwargs傳遞任意參數):io
def wrapper(*args, **kwargs): 前置操做 func = function(*args, **kwargs)(即函數模板) 後置操做 return func
func = function(*args, **kwargs) 使咱們獲得了函數執行的結果,不管這個函數是什麼函數,而return func將結果返回,連同先後的操做一塊兒做爲wrapper扔出去。function
P3 一個例子
好了,接下來咱們來寫個例子,一個計算執行時長的裝飾器:
import time def simple_timeit(function): def wrapper(*args, **kwargs): start = time.time() # 記錄開始時間 func = function(*args, **kwargs) print("用時%.4fs"%(time.time() - start)) # 輸出(結束時間-開始時間) return func return wrapper
如今咱們隨便寫兩個函數,並給它們裝上裝飾器:
@simple_timeit def sleep(): # 無參數函數 time.sleep(3) return "Get up!!!"
@simple_timeit def break_str(string): # 有參數函數 txt = [t.upper() for t in string.split(" ")] return txt
執行一下看看結果:
能夠看到對於不一樣的函數類型,咱們的計時器都是通用的。
總的來講,裝飾器能讓咱們的代碼變得簡潔,並且能在多個函數上通用。再者因爲它是在函數之上額外附加的操做,因此咱們只要將裝飾器那一行註釋掉就能關閉附加功能,而又不影響函數本體的功能,能夠說很是方便啦,因此有機會仍是值得一用的~