Python中decorator使用執行個體

來源:互聯網
上載者:User
在我以前介紹 Python 2.4 特性的Blog中已經介紹過了decorator了,不過,那時是照貓畫虎,現在再仔細描述一下它的使用。

關於decorator的詳細介紹在 Python 2.4中的What's new中已經有介紹,大家可以看一下。

如何調用decorator

基本上調用decorator有兩種形式

第一種:
複製代碼 代碼如下:


@A
def f ():

這種形式是decorator不帶參數的寫法。最終 Python 會處理為:
複製代碼 代碼如下:


f = A(f)


還可以擴充成:
複製代碼 代碼如下:


@A
@B
@C
def f ():

最終 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都對應有相應的函數,它要對後面的函數進行處理,要麼返回原來的函數對象,要麼返回一個新的函數對象。請注意,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的魔力是什嗎?適合在哪些場合呢?是否我需要使用它呢?

decorator的魔力就是它可以對所修飾的函數進行加工。那麼這種加工是在不改變原來函數代碼的情況下進行的。有點象我知道那麼一點點的AOP(面向方面編程)的想法。

它適合的場合我能想到的列舉出下:

1.象文檔中所說,最初是為了使調用staticmethod和classmethod這樣的方法更方便
2.在某些函數執行前做一些工作,如web開發中,許多函數在調用前需要先檢查一下使用者是否已經登入,然後才能調用
3.在某此函數執行後做一些工作,如調用完畢後,根據返回狀態寫日誌
4.做參數檢查

可能還有許多,你可以自由發揮想象

那麼我需要用它嗎?

我想那要看你了。不過,我想在某些情況下,使用decorator可以增加程式的靈活性,減少耦合度。比如前面所說的使用者登入檢查。的確可以寫一個通用的登入檢查函數,然後在每個函數中進行調用。但這樣會造成函數不夠靈活,而且增加了與其它函數之間的結合程度。如果使用者登入檢查功能有所修改,比如傳回值的判斷髮生了變化,有可能每個用到它的函數都要修改。而使用decorator不會造成這一問題。同時使用decorator的文法也使得代碼簡單,清晰(一但你熟悉它的文法的話)。當然你不使用它是可以的。不過,這種函數之間相互結合的方式,更符合搭積木的要求,它可以把函數功能進一步分解,使得功能足夠簡單和單一。然後再通過decorator的機制靈活的把相關的函數串成一個串,這麼一想,還真是不錯。比如下面:
複製代碼 代碼如下:


@A
@B
def account(args):pass

假設這是一個記帳處理函數,account只管記帳。但一個真正的記帳還有一些判斷和處理,比如:B檢查帳戶狀態,A記日誌。這樣的效果其實是先檢查B、通過在A中的處理可以先執行account,然後再進行記日誌的處理。象搭積木一樣很方便,改起來也容易。甚至可以把account也寫成decorator,而下面執行的函數是一個空函數。然後再通過設定檔等方法,將decorator的組合儲存起來,就基本實現功能的組裝化。是不是非常理想。

Python 帶給人的創造力真是無窮啊!

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.