Python學習 decorator的使用

2021-08-30 08:13:48 字數 3265 閱讀 8885

在我以前介紹 python 2.4 特性的blog中已經介紹過了decorator了,不過,那時是照貓畫虎,現在再仔細描述一下它的使用。

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

如何呼叫decorator

基本上呼叫decorator有兩種形式

第一種:

@adef f ():

...這種形式是decorator不帶引數的寫法。最終 python 會處理為:

f = a(f)

還可以擴充套件成:

@a@b

@cdef 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

@adef f(args):pass

上面是對func處理後,仍返回原函式物件。這個decorator函式的引數為要處理的函式。如果要返回乙個新的函式,可以為:

def a(func):

def new_func(args):

#做一些額外的工作

return func(args) #呼叫原函式繼續進行處理

return new_func

@adef f(args):pass

要注意 new_func的定義形式要與待處理的函式相同,因此還可以寫得通用一些,如:

def a(func):

def new_func(*args, **argkw):

#做一些額外的工作

return func(*args, **argkw) #呼叫原函式繼續進行處理

return new_func

@adef 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

@adef 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(面向方面程式設計)的想法。

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

象文件中所說,最初是為了使呼叫staticmethod和classmethod這樣的方法更方便

在某些函式執行前做一些工作,如web開發中,許多函式在呼叫前需要先檢查一下使用者是否已經登入,然後才能呼叫

在某此函式執行後做一些工作,如呼叫完畢後,根據返回狀態寫日誌

做引數檢查

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

那麼我需要用它嗎?

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

@a@b

def account(args):pass

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

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

理解python函式裝飾器 decorator

函式裝飾器是python有別於其他語言的主要特徵之一,這也是充分發揮了動態語言的優勢,可以使我們在編寫程式時更加簡潔。但最開始接觸函式裝飾器有點難以理解,本文盡量用簡單的語言來理解函式裝飾器。在理解函式裝飾器之前,最好儲備並理解了以下python的基礎知識 生活中,化妝可能是最容易理解裝飾行為的例子...

學習 Python學習(一) Python問答

一.為什麼要使用python?python的主要特點有 1 軟體質量,python 具有很強的可讀性,因此在重用和維護方面就比較方便 2 編碼效率,python沒有編譯和鏈結庫的過程 3 程式移植性,不做任何修改,python可執行在windows和linux系統 4 豐富的支撐庫,python既可...

python學習清單大全 python學習清單

學習單子 a部 python 大神vamei的blog之python篇 大神vamei的部落格很是推薦 各方面寫的都很好 我暫時只是看過他的python 網路和django的部分,看下來簡單易懂,很適合做個學習的大綱,然後靠自己日後不斷的充實進去。文章中也簡要的列出常用的一些命令語法之類的。pyth...