Python的裝飾器可以實現在程式碼執行期間修改函式的上下文, 即可以定義函式在執行之前進行何種操作和函式執行後進行何種操作, 而函式本身並沒有任何的改變。
這個看起來很複雜, 實際上應用到了我之前說過的閉包的概念, 仔細看一看, 其實並不複雜。
首先, 我們先定義一個函式, 這個函式可以輸出我的個人暱稱:
1 2 3 |
def my_name(): print "Yi_Zhi_Yu" my_name() # Yi_Zhi_Yu |
那假如我需要在個人暱稱輸出前, 在輸出我的個人uid呢, 當然, 要求是不改動現有的my_name函式, 這個時候就可以使用裝飾器了
首先, 裝飾器也是個函式, 其次, 他需要接受一個引數,該參數列示了要被裝飾的函式(即my_name):
1 2 3 4 5 |
def my_info(func): def wrapper(*args, **params): print 218 return func(*args, **params) return wrapper |
然後與相應的被裝飾函式關聯起來的方法就是使用@my_info
寫在被裝飾函式的前面
1 2 3 |
@my_info def my_name(): print "Yi_Zhi_Yu" |
最後, 在執行my_name的時候, 就能既輸出我的uid, 又能輸出我的暱稱了
1 2 3 |
my_name() #218 #Yi_Zhi_Yu |
在上面, 最讓我們疑惑的是裝飾器函式定義裡面的wrapper函式, 裝飾器本身返回的是wrapper函式的定義, 而wrapper中則定義了對被裝飾函式(my_name)的呼叫, func表示的就是被裝飾函式, 說白了, 裝飾器只是把某個不得改動的函式(a)放到另一個函式(b)中, 在b裡面呼叫a, 在呼叫前後就可以做所謂的看起來像裝飾的工作了。
my_info的最終返回的wrapper函式的定義, 並不是執行結果,只有當wrapper真正執行的時候, 才會真正的執行my_name方法, 這就是閉包時所說的內容。
wrapper中的引數, 實際上則是傳遞給func(實際上是my_name)的引數
因為裝飾器也是個函式, 那麼裝飾器自己的能不能有引數傳遞呢。可以, 不過需要定義一個更高階的函式, 也就是外面還要套一層函式, 比如, 我還要輸出我的自定義的一個資訊,需要傳遞引數
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
def c_info(text): def my_info(func): def wrapper(*args, **params): print text print 218 return func(*args, **params) return wrapper return my_info #使用裝飾器 @c_info("Tony") def my_name(): print "Yi_Zhi_Yu" my_name() #Tony #218 #Yi_Zhi_Yu |
與前面的那個裝飾器相比, 僅僅是多了個外層, 內層也僅僅是增加了對外層傳入引數(text)的呼叫
總而言之, Python在函式定義中支援了對oop思想中的裝飾器的實現, 其本質也只是使用了閉包的思路, 延遲呼叫, 並在呼叫前後增加自己的其他實現內容
Ps: 以上皆為學習筆記, 附帶自己的理解, 難免有偏差, 如有發現紕漏, 還望指正