來自:limodou的學習記錄 python
在我之前介紹 Python 2.4 特性的Blog中已經介紹過了decorator了,不過,那時是照貓畫虎,如今再仔細描述一下它的使用。 編程
關於decorator的詳細介紹在 Python 2.4中的What’s new中已經有介紹,你們能夠看一下。 函數
基本上調用decorator有兩種形式 學習
@A
def f ():
… spa
這種形式是decorator不帶參數的寫法。最終 Python 會處理爲: .net
f = A(f) 日誌
還能夠擴展成: orm
最終 Python 會處理爲:
f = A(B(C(f)))
注:文檔上寫的是@A @B @C的形式,但其實是不行的,要寫成多行。
並且執行順序是按函數調用順序來的,先最下面的C,而後是B,而後是A。所以,若是decorator有順序話,必定要注意:先要執行的放在最下面,最後執行的放在最上面。
(應該不存在這種倒序的關係)
@A(args)
def f ():
…
這種形式是decorator帶參數的寫法。那麼 Python 會處理爲:
def f(): …
_deco = A(args)
f = _deco(f)
能夠看出, Python 會先執行A(args)獲得一個decorator函數,而後再按與第一種同樣的方式進行處理。
每個decorator都對應有相應的函數,它要對後面的函數進行處理,要麼返回原來的函數對象,要麼返回一個新的函數對象。請注意,decorator只用來處理函數和類方法。
針對於第一種調用形式
def A(func):
#處理func
#如func.attr=’decorated’
return func
@A
def f(args):pass
上面是對func處理後,仍返回原函數對象。這個decorator函數的參數爲要處理的函數。若是要返回一個新的函數,能夠爲:
def A(func):
def new_func(args):
#作一些額外的工做
return func(args) #調用原函數繼續進行處理
return new_func
@A
def f(args):pass
要注意 new_func的定義形式要與待處理的函數相同,所以還能夠寫得通用一些,如:
def A(func):
def new_func(*args, **argkw):
#作一些額外的工做
return func(*args, **argkw) #調用原函數繼續進行處理
return new_func
@A
def f(args):pass
能夠看出,在A中定義了新的函數,而後A返回這個新的函數。在新函數中,先處理一些事情,好比對參數進行檢查,或作一些其它的工做,而後再調原始的函數進行處理。這種模式能夠當作,在調用函數前,經過使用decorator技術,能夠在調用函數以前進行了一些處理。若是你想在調用函數以後進行一些處理,或者再進一步,在調用函數以後,根據函數的返回值進行一些處理能夠寫成這樣:
def A(func):
def new_func(*args, **argkw):
result = func(*args, **argkw) #調用原函數繼續進行處理
if result:
#作一些額外的工做
return new_result
else:
return result
return new_func
@A
def f(args):pass
針對第二種調用形式
在文檔上說,若是你的decorator在調用時使用了參數,那麼你的decorator函數只會使用這些參數進行調用,所以你須要返回一個新的decorator函數,這樣就與第一種形式一致了。
def A(arg):
def _A(func):
def new_func(args):
#作一些額外的工做
return func(args)
return new_func
return _A
@A(arg)
def f(args):pass
能夠看出A(arg)返回了一個新的 decorator _A。
不過我也一直在想,到底decorator的魔力是什麼?適合在哪些場合呢?是否我須要使用它呢?
decorator的魔力就是它能夠對所修飾的函數進行加工。那麼這種加工是在不改變原來函數代碼的狀況下進行的。有點象我知道那麼一點點的AOP(面向方面編程)的想法。
它適合的場合我能想到的列舉出下:
可能還有許多,你能夠自由發揮想象
那麼我須要用它嗎?
我想那要看你了。不過,我想在某些狀況下,使用decorator能夠增長程序的靈活性,減小耦合度。好比前面所說的用戶登陸檢查。的確能夠寫一個通用的登陸檢查函數,而後在每一個函數中進行調用。但這樣會形成函數不夠靈活,並且增長了與其它函數之間的結合程度。若是用戶登陸檢查功能有所修改,好比返回值的判斷髮生了變化,有可能每一個用到它的函數都要修改。而使用decorator不會形成這一問題。同時使用decorator的語法也使得代碼簡單,清晰(一但你熟悉它的語法的話)。固然你不使用它是能夠的。不過,這種函數之間相互結合的方式,更符合搭積木的要求,它能夠把函數功能進一步分解,使得功能足夠簡單和單一。而後再經過decorator的機制靈活的把相關的函數串成一個串,這麼一想,還真是不錯。好比下面:
@A
@B
def account(args):pass
假設這是一個記賬處理函數,account只管記賬。但一個真正的記賬還有一些判斷和處理,好比:B檢查賬戶狀態,A記日誌。這樣的效果實際上是先檢查B、經過在A中的處理能夠先執行account,而後再進行記日誌的處理。象搭積木同樣很方便,改起來也容易。甚至能夠把account也寫成decorator,而下面執行的函數是一個空函數。而後再經過配置文件等方法,將decorator的組合保存起來,就基本實現功能的組裝化。是否是很是理想。
Python 帶給人的創造力真是無窮啊!