Python的函數和方法裝飾漫談(Function decorator)

裝飾方法的產生:

Python2.2通過增加靜態方法和類方法擴展了Python的對象模型。但是當時沒有提供一個簡化的語法去定義static/class方法,只得在定義好的方法尾部去調用staticmethod()/classmethod()方法達到目的。例如:
class C:
   def meth (cls):
       
   meth = classmethod(meth)   # 使meth方法成爲類方法
但是這樣會造成一個問題:當一個方法比較長時,很容易忘記尾部的調用。爲了簡化這個操作一個新的語法被加了進來:方法裝飾,以@開頭後跟裝飾方 法名,如@staticmethod/@classmethod,由此產生出decorator方法及decorator模式。現在我們可以這樣寫:
 
class C:
   @classmethod
   def meth (cls):
   
可以對一個方法應用多個裝飾方法:
 
@A
@B
@C
def f ():
    
#等價於下面的形式,Python會按照應用次序依次調用裝飾方法(最近的先調用)
def f(): 
f = A(B(C(f)))
 
 
裝飾方法解析: 
每個decorator只是一個方法, 可以是自定義的或者內置的(如內置的@staticmethod/@classmethod)。decorator方法把要裝飾的方法作爲輸入參數,在函 數體內可以進行任意的操作(可以想象其中蘊含的威力強大,會有很多應用場景),只要確保最後返回一個可執行的函數即可(可以是原來的輸入參數函數, 或者是一個新函數)。decorator的作用對象可以是模塊級的方法或者類方法。decorator根據應用時的參數個數不同分爲兩類:無參數 decorator,有參數decorator。下面分別介紹。
無參數decorator:
 
  1. def deco(func): 
  2.     """無參數調用decorator聲明時必須有一個參數,這個參數將接收要裝飾的方法""" 
  3.     print "Enter decorator"     #進行額外操作 
  4.     func.attr = 'decorated'     #對函數進行操作,增加一個函數屬性 
  5.     return func   #返回一個可調用對象(此例還是返回作爲輸入參數的方法) 
  6.                       #返回一個新函數時,新函數可以是一個全局方法或者decorator函數的內嵌函數, 
  7.                       #只要函數的簽名和被裝飾的函數相同 
  8.  
  9. @deco 
  10. def MyFunc():   #應用@deco修飾的方法 
  11.     print "Enter MyFunc" 
  12.  
  13. MyFunc()     #調用被裝飾的函數 
 注意:當使用上述方法定義一個decorator方法時,函數體內的額外操作只在被裝飾的函數首次調用時執行,如果要保證額外操作在每次調用被裝飾的函數時都執行,需要換成如下的寫法:
 
  1. def deco(func): 
  2.     def replaceFunc():     #定義一個內嵌函數,此函數包裝了被裝飾的函數,並提供額外操作的代碼 
  3.         print "Enter decorator"     #進行額外操作 
  4.         return func()    #產生對被裝飾函數的調用 
  5.     return replaceFunc   #由於返回的是這個新的內嵌函數,所以確保額外操作每次調用得以運行 
  6.  
  7. @deco 
  8. def MyFunc():   #應用@deco修飾的方法 
  9.     print "Enter MyFunc" 
  10.  
  11. MyFunc()     #調用被裝飾的函數 
 
 有參數decorator:

  1. def decoWithArgs(arg): 
  2.     """由於有參數的decorator函數在調用時只會使用應用時的參數而不接收被裝飾的函數做爲參數, 
  3.        所以必須返回一個decorator函數, 由它對被裝飾的函數進行封裝處理""" 
  4.     def newDeco(func):    #定義一個新的decorator函數 
  5.         def replaceFunc():    #在decorator函數裏面再定義一個內嵌函數,由它封裝具體的操作 
  6.             print "Enter decorator"     #進行額外操作 
  7.             return func()    #對被裝飾函數進行調用 
  8.         return replaceFunc 
  9.     return newDeco    #返回一個新的decorator函數 
  10.  
  11. @decoWithArgs("demo"
  12. def MyFunc():    #應用@decoWithArgs修飾的方法 
  13.     print "Enter MyFunc" 
  14.      
  15. MyFunc()    #調用被裝飾的函數
 
 
當我們對某個方法應用了裝飾方法後, 其實就改變了被裝飾函數名稱所引用的函數代碼塊入口點,使其重新指向了由裝飾方法所返回的函數入口點。由此我們可以用decorator改變某個原有函數的功能,添加各種操作,或者完全改變原有實現。

由 quke.cn 在 2008-11-10 02:35:34 做最後一次更新!

發佈了74 篇原創文章 · 獲贊 6 · 訪問量 42萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章