無參數裝飾器
對於python小白來說,python的裝飾器簡直讓人懵逼,不知如何理解,其實按照裝飾器的字面意思,
就是把自己定義的函數裝飾一遍,然后返回一個新的函數(注意是新的,已經不是本來定義的函數了)
為什么這么說,我用一個裝飾器最原始的例子來說明,看一下代碼:
1 #裝飾函數 2 def decorator(foo): 3 def wrapper(): 4 print 'wrapper' 5 return foo() 6 return wrapper 7 8 #自定義函數 9 def abc(): 10 print 'abc' 11 12 #裝飾abc 13 abc = decorator(abc)
以上就是裝飾器的過程,可以看出調用decorator函數,返回的是wrapper函數對象,而不是abc這個函數對象,
abc這個函數在wrapper中已經是被調用了的,只是返回一個結果。以上代碼的運行結果如下圖,可以看出裝飾
之后的abc是wrapper的函數對象,而不是原來函數了。

而python的語法糖'@'就是執行了以上的過程,下面的代碼和上面的代碼原理是一樣的:
1 def decorator(foo): 2 def wrapper(): 3 print 'wrapper' 4 return foo() 5 return wrapper 6 7 @decorator 8 def abc(): 9 print 'abc'
python的裝飾器語法就是自動調用decorator函數,並以自定義的函數abc函數對象為參數,
返回wrapper函數對象,這樣一個過程。
帶參數的裝飾器:
接下來,再深一步來說說帶參數的裝飾器, 其實這個只比上面那個無參數裝飾器多了一步,
就是先調用裝飾器函數,再返回真正的裝飾器,之后的步驟和無參數的一樣了,說得太抽象?
直接上代碼,這樣就明顯了,先調用用最外層的函數,返回的是一個真正的裝飾器,然后像
之前無參數的時候一樣,修飾abc函數后返回新的函數對象。
1 def decoratorFunc(arg): 2 def decorator(foo): 3 def wrapper(): 4 if arg == 0: 5 print 'lalala' 6 return foo() 7 return wrapper 8 return decorator 9 10 deco0 = decoratorFunc(0) 11 deco1 = decoratorFunc(1) 12 13 abc0 = deco0(abc) 14 abc1 = deco1(abc)
然后python的語法糖的過程也是像上面那樣了,所以我得出一個結論,就是@后面一定是一個
函數對象,而非函數調用!
1 @decoratorFunc(0) 2 def abc(): 3 print 'abc'
最后
寫更普通的裝飾器,如果被裝飾的函數有參數怎么辦?很簡單,利用python的可變長度參數就行。
注意,是在wrapper這個函數上我們寫上python的可變長度參數,而裝飾器函數decorator的參數
永遠只有一個,就是函數對象。看以下代碼,是無參數裝飾器的例子,如果是帶參數的函數,也只
需要把wrapper改成接收可變長度參數就行。
1 def decorator(foo): 2 def wrapper(*args, **kwargs): 3 print 'wrapper' 4 return foo(*args, **kwargs) 5 retrun wrapper 6 7 8 @decorator 9 def abc(arg): 10 print 'abc:', arg
作者:陳棟權
時間:2016/09/05
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,
且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
如有特別用途,請與我聯系郵箱:kingchen.gd@foxmail.com
最后有興趣的同學可以關注我的微信公眾號,可以隨時及時方便看我的文章。*^_^*
掃碼關注或者搜索微信號:King_diary

