黄色网页视频 I 影音先锋日日狠狠久久 I 秋霞午夜毛片 I 秋霞一二三区 I 国产成人片无码视频 I 国产 精品 自在自线 I av免费观看网站 I 日本精品久久久久中文字幕5 I 91看视频 I 看全色黄大色黄女片18 I 精品不卡一区 I 亚洲最新精品 I 欧美 激情 在线 I 人妻少妇精品久久 I 国产99视频精品免费专区 I 欧美影院 I 欧美精品在欧美一区二区少妇 I av大片网站 I 国产精品黄色片 I 888久久 I 狠狠干最新 I 看看黄色一级片 I 黄色精品久久 I 三级av在线 I 69色综合 I 国产日韩欧美91 I 亚洲精品偷拍 I 激情小说亚洲图片 I 久久国产视频精品 I 国产综合精品一区二区三区 I 色婷婷国产 I 最新成人av在线 I 国产私拍精品 I 日韩成人影音 I 日日夜夜天天综合

Python中decorator使用實(shí)例

系統(tǒng) 1984 0

在我以前介紹 Python 2.4 特性的Blog中已經(jīng)介紹過(guò)了decorator了,不過(guò),那時(shí)是照貓畫虎,現(xiàn)在再仔細(xì)描述一下它的使用。

關(guān)于decorator的詳細(xì)介紹在 Python 2.4中的What's new中已經(jīng)有介紹,大家可以看一下。

如何調(diào)用decorator

基本上調(diào)用decorator有兩種形式

第一種:

復(fù)制代碼 代碼如下:

@A
def f ():

這種形式是decorator不帶參數(shù)的寫法。最終 Python 會(huì)處理為:

復(fù)制代碼 代碼如下:

f = A(f)

還可以擴(kuò)展成:
復(fù)制代碼 代碼如下:

@A
@B
@C
def f ():
???

最終 Python 會(huì)處理為:

復(fù)制代碼 代碼如下:

f = A(B(C(f)))

注:文檔上寫的是@A @B @C的形式,但實(shí)際上是不行的,要寫成多行。而且執(zhí)行順序是按函數(shù)調(diào)用順序來(lái)的,先最下面的C,然后是B,然后是A。因此,如果decorator有順序話,一定要注意:先要執(zhí)行的放在最下面,最后執(zhí)行的放在最上面。(應(yīng)該不存在這種倒序的關(guān)系)

第二種:

復(fù)制代碼 代碼如下:

@A(args)
def f ():
???

這種形式是decorator帶參數(shù)的寫法。那么 Python 會(huì)處理為:

復(fù)制代碼 代碼如下:

def f():
_deco = A(args)
f = _deco(f)

可以看出, Python 會(huì)先執(zhí)行A(args)得到一個(gè)decorator函數(shù),然后再按與第一種一樣的方式進(jìn)行處理。

decorator函數(shù)的定義

每一個(gè)decorator都對(duì)應(yīng)有相應(yīng)的函數(shù),它要對(duì)后面的函數(shù)進(jìn)行處理,要么返回原來(lái)的函數(shù)對(duì)象,要么返回一個(gè)新的函數(shù)對(duì)象。請(qǐng)注意,decorator只用來(lái)處理函數(shù)和類方法。

第一種:
針對(duì)于第一種調(diào)用形式

復(fù)制代碼 代碼如下:

def A(func):
??? #處理func
??? #如func.attr='decorated'
??? return func
@A
def f(args):pass

上面是對(duì)func處理后,仍返回原函數(shù)對(duì)象。這個(gè)decorator函數(shù)的參數(shù)為要處理的函數(shù)。如果要返回一個(gè)新的函數(shù),可以為:

復(fù)制代碼 代碼如下:

def A(func):
??? def new_func(args):
??????? #做一些額外的工作
??????? return func(args) #調(diào)用原函數(shù)繼續(xù)進(jìn)行處理
??? return new_func
@A
def f(args):pass

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

復(fù)制代碼 代碼如下:

def A(func):
??? def new_func(*args, **argkw):
??????? #做一些額外的工作
??????? return func(*args, **argkw) #調(diào)用原函數(shù)繼續(xù)進(jìn)行處理
??? return new_func
@A
def f(args):pass

可以看出,在A中定義了新的函數(shù),然后A返回這個(gè)新的函數(shù)。在新函數(shù)中,先處理一些事情,比如對(duì)參數(shù)進(jìn)行檢查,或做一些其它的工作,然后再調(diào)原始的函數(shù)進(jìn)行處理。這種模式可以看成,在調(diào)用函數(shù)前,通過(guò)使用decorator技術(shù),可以在調(diào)用函數(shù)之前進(jìn)行了一些處理。如果你想在調(diào)用函數(shù)之后進(jìn)行一些處理,或者再進(jìn)一步,在調(diào)用函數(shù)之后,根據(jù)函數(shù)的返回值進(jìn)行一些處理可以寫成這樣:

復(fù)制代碼 代碼如下:

def A(func):
??? def new_func(*args, **argkw):
??????? result = func(*args, **argkw) #調(diào)用原函數(shù)繼續(xù)進(jìn)行處理
??????? if result:
??????????? #做一些額外的工作
??????????? return new_result
??????? else:
??????????? return result
??? return new_func
@A
def f(args):pass

第二種:
針對(duì)第二種調(diào)用形式

在文檔上說(shuō),如果你的decorator在調(diào)用時(shí)使用了參數(shù),那么你的decorator函數(shù)只會(huì)使用這些參數(shù)進(jìn)行調(diào)用,因此你需要返回一個(gè)新的decorator函數(shù),這樣就與第一種形式一致了。

復(fù)制代碼 代碼如下:

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)返回了一個(gè)新的 decorator _A。

decorator的應(yīng)用場(chǎng)景

不過(guò)我也一直在想,到底decorator的魔力是什么?適合在哪些場(chǎng)合呢?是否我需要使用它呢?

decorator的魔力就是它可以對(duì)所修飾的函數(shù)進(jìn)行加工。那么這種加工是在不改變?cè)瓉?lái)函數(shù)代碼的情況下進(jìn)行的。有點(diǎn)象我知道那么一點(diǎn)點(diǎn)的AOP(面向方面編程)的想法。

它適合的場(chǎng)合我能想到的列舉出下:

1.象文檔中所說(shuō),最初是為了使調(diào)用staticmethod和classmethod這樣的方法更方便
2.在某些函數(shù)執(zhí)行前做一些工作,如web開(kāi)發(fā)中,許多函數(shù)在調(diào)用前需要先檢查一下用戶是否已經(jīng)登錄,然后才能調(diào)用
3.在某此函數(shù)執(zhí)行后做一些工作,如調(diào)用完畢后,根據(jù)返回狀態(tài)寫日志
4.做參數(shù)檢查

可能還有許多,你可以自由發(fā)揮想象

那么我需要用它嗎?

我想那要看你了。不過(guò),我想在某些情況下,使用decorator可以增加程序的靈活性,減少耦合度。比如前面所說(shuō)的用戶登錄檢查。的確可以寫一個(gè)通用的登錄檢查函數(shù),然后在每個(gè)函數(shù)中進(jìn)行調(diào)用。但這樣會(huì)造成函數(shù)不夠靈活,而且增加了與其它函數(shù)之間的結(jié)合程度。如果用戶登錄檢查功能有所修改,比如返回值的判斷發(fā)生了變化,有可能每個(gè)用到它的函數(shù)都要修改。而使用decorator不會(huì)造成這一問(wèn)題。同時(shí)使用decorator的語(yǔ)法也使得代碼簡(jiǎn)單,清晰(一但你熟悉它的語(yǔ)法的話)。當(dāng)然你不使用它是可以的。不過(guò),這種函數(shù)之間相互結(jié)合的方式,更符合搭積木的要求,它可以把函數(shù)功能進(jìn)一步分解,使得功能足夠簡(jiǎn)單和單一。然后再通過(guò)decorator的機(jī)制靈活的把相關(guān)的函數(shù)串成一個(gè)串,這么一想,還真是不錯(cuò)。比如下面:

復(fù)制代碼 代碼如下:

@A
@B
def account(args):pass

假設(shè)這是一個(gè)記帳處理函數(shù),account只管記帳。但一個(gè)真正的記帳還有一些判斷和處理,比如:B檢查帳戶狀態(tài),A記日志。這樣的效果其實(shí)是先檢查B、通過(guò)在A中的處理可以先執(zhí)行account,然后再進(jìn)行記日志的處理。象搭積木一樣很方便,改起來(lái)也容易。甚至可以把a(bǔ)ccount也寫成decorator,而下面執(zhí)行的函數(shù)是一個(gè)空函數(shù)。然后再通過(guò)配置文件等方法,將decorator的組合保存起來(lái),就基本實(shí)現(xiàn)功能的組裝化。是不是非常理想。

Python 帶給人的創(chuàng)造力真是無(wú)窮啊!


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論