Python裝飾器

什么是裝飾器饼丘?

類似于Java的注解夸浅。在python中叫做裝飾器仑最,目的是用于對(duì)已存在代碼進(jìn)行修改。這里的修改是狹義的帆喇,并非任意的修改警医,而是能夠?qū)ζ鋱?zhí)行過程進(jìn)行編譯時(shí)修改。

最簡(jiǎn)單示例

def DecoratorTest(fun):
    def _T_fun_(id):
        print("before call -----")
        fun(id)
        print("after call -----")
    return _T_fun_

@DecoratorTest
def OutputX(id):
    print(id)

OutputX(20)

輸出結(jié)果:

before call -----
20
after call -----

在沒有使用裝飾器之前坯钦,輸出20,使用裝飾器之后预皇,實(shí)現(xiàn)了對(duì)OutputX函數(shù)的邏輯修改,這個(gè)就是裝飾器的作用婉刀。

有什么用吟温?

雖然前一個(gè)章節(jié)中,大致說明了裝飾器的用法突颊,但很多人還是不會(huì)用鲁豪,原因在于不知道到底這個(gè)功能應(yīng)該應(yīng)用于什么場(chǎng)景。如果螺絲刀只是被描述為一頭是一字形或十字形的器具律秃,可能即使遇到一個(gè)螺絲爬橡,都不會(huì)想到螺絲刀,所以將工具與場(chǎng)景緊密關(guān)聯(lián)是很重要的棒动。裝飾器常用的就兩個(gè)場(chǎng)景:

  1. 構(gòu)建流程注入糙申,例如注入日志、性能分析處理船惨;
  2. 程序擴(kuò)展實(shí)現(xiàn)柜裸,適合在處理流程中添加具體擴(kuò)展實(shí)現(xiàn),實(shí)現(xiàn)類似回調(diào)功能粱锐;

怎么用疙挺?

流程注入

假設(shè)一個(gè)場(chǎng)景:設(shè)計(jì)了一個(gè)系統(tǒng),希望在某個(gè)場(chǎng)景下可以記錄系統(tǒng)內(nèi)函數(shù)的執(zhí)行過程信息怜浅,幫助進(jìn)行問題定位衔统,實(shí)現(xiàn)類似日志的功能。
簡(jiǎn)化原系統(tǒng)實(shí)現(xiàn)如下:

def FunA(a):
  return a+20
def FunB(a, b):
  return a+b
def FunC(a, b):
  return FunA(a)+FunB(a, b)

print(FunC(30,40))

輸出結(jié)果為:

120

這時(shí)海雪,發(fā)現(xiàn)輸出數(shù)字與預(yù)期不相符,怎么辦舱殿?除了調(diào)試奥裸,如果希望通過日志來定位解決問題,那么修改系統(tǒng)實(shí)現(xiàn)如下:

def AFun(fun):
    def CallBack(*args, **args2):
        print("befor call "+getattr(fun,"__name__"))
        ret = fun(*args, **args2)
        if ret is not None:
            print("Return:")
            print(ret)
        print("befor call "+getattr(fun,"__name__"))
        return ret
    return CallBack
        
@AFun
def FunA(a):
  return a+20
@AFun
def FunB(a, b):
  return a+b
@AFun
def FunC(a, b):
  return FunA(a)+FunB(a, b)

print(FunC(30,40))

最終輸出如下:

befor call FunC
befor call FunA
Return:
50
befor call FunA
befor call FunB
Return:
70
befor call FunB
Return:
120
befor call FunC
120

通過這種方式沪袭,在不修改原代碼邏輯的基礎(chǔ)上湾宙,添加了日志執(zhí)行輸出功能樟氢,還可以對(duì)調(diào)用過程進(jìn)行時(shí)間統(tǒng)計(jì),分析系統(tǒng)的性能瓶頸侠鳄。

擴(kuò)展實(shí)現(xiàn)

假設(shè)場(chǎng)景:假設(shè)設(shè)計(jì)一個(gè)web框架埠啃,最起碼一個(gè)需求就是用戶可以擴(kuò)展定義響應(yīng)鏈接,例如響應(yīng)“/a/b"的"get"請(qǐng)求伟恶。有兩種設(shè)計(jì)方式碴开,先看正常常規(guī)設(shè)計(jì)方式:

url_processors = {}
def WebEngine(url, method):
    if url in url_processors and method in url_processors[url]:
        return url_processors[url][method]()
    else:
        return 404

def ProcessA():
    print("in process A")
    return "Hello A"

url_processors["/A"] = {}
url_processors["/A"]["get"] = ProcessA

print(WebEngine("/A", "get"))
print(WebEngine("/B", "get"))

執(zhí)行輸出結(jié)果如下:

in process A
Hello A
404

從上邊看到,修改響應(yīng)信息博秫,需要維護(hù)兩個(gè)地方的代碼潦牛,容易帶來不一致問題,也提升了維護(hù)成本挡育。利用裝飾器如何解決這個(gè)問題巴碗,代碼示例如下:

url_processors = {}
def WebEngine(url, method):
    global url_processors
    if url in url_processors and method in url_processors[url]:
        return url_processors[url][method]()
    else:
        return 404

def DeclMethod( url="", method=""):
    def DSF(fun):
        global url_processors
        
        url_processors[url] = {}
        url_processors[url][method] = fun
    return DSF


@DeclMethod(url="/A", method="get")
def ProcessA():
    print("in process A")
    return "Hello A"

print(WebEngine("/A", "get"))
print(WebEngine("/B", "get"))

從代碼上看,擴(kuò)展一個(gè)響應(yīng)即寒,只需要在函數(shù)前添加具體的擴(kuò)展裝飾聲明即可橡淆。執(zhí)行結(jié)果如下:

in process A
Hello A
404

總結(jié)

在學(xué)習(xí)過程中,需要將工具與場(chǎng)景進(jìn)行聯(lián)系母赵,在場(chǎng)景的解決實(shí)踐中逸爵,會(huì)發(fā)現(xiàn)很多其他不足,例如在上例中市咽,涉及了不定長(zhǎng)參數(shù)的處理痊银,裝飾器參數(shù)的處理。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末施绎,一起剝皮案震驚了整個(gè)濱河市溯革,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌谷醉,老刑警劉巖致稀,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異俱尼,居然都是意外死亡抖单,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門遇八,熙熙樓的掌柜王于貴愁眉苦臉地迎上來矛绘,“玉大人,你說我怎么就攤上這事刃永』醢” “怎么了?”我有些...
    開封第一講書人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵斯够,是天一觀的道長(zhǎng)囚玫。 經(jīng)常有香客問我喧锦,道長(zhǎng),這世上最難降的妖魔是什么抓督? 我笑而不...
    開封第一講書人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任燃少,我火速辦了婚禮,結(jié)果婚禮上铃在,老公的妹妹穿的比我還像新娘阵具。我一直安慰自己,他們只是感情好涌穆,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開白布怔昨。 她就那樣靜靜地躺著,像睡著了一般宿稀。 火紅的嫁衣襯著肌膚如雪趁舀。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評(píng)論 1 291
  • 那天祝沸,我揣著相機(jī)與錄音矮烹,去河邊找鬼。 笑死罩锐,一個(gè)胖子當(dāng)著我的面吹牛奉狈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播涩惑,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼仁期,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了竭恬?” 一聲冷哼從身側(cè)響起跛蛋,我...
    開封第一講書人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎痊硕,沒想到半個(gè)月后赊级,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡岔绸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年理逊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盒揉。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡晋被,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出刚盈,到底是詐尸還是另有隱情墨微,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布扁掸,位于F島的核電站翘县,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏谴分。R本人自食惡果不足惜锈麸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望牺蹄。 院中可真熱鬧忘伞,春花似錦、人聲如沸沙兰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)鼎天。三九已至舀奶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間斋射,已是汗流浹背育勺。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留罗岖,地道東北人涧至。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像桑包,于是被迫代替她去往敵國(guó)和親南蓬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容

  • 本文轉(zhuǎn)自http://mingxinglai.com/cn/2015/08/python-decorator/ [...
    Jlan閱讀 550評(píng)論 0 5
  • 裝飾器是程序開發(fā)中經(jīng)常會(huì)用到的一個(gè)功能哑了,功能就是在運(yùn)行原來功能基礎(chǔ)上赘方,加上一些其它功能,比如權(quán)限的驗(yàn)證垒手,比如日志的...
    壁花燒年閱讀 250評(píng)論 0 0
  • 在python編程中蒜焊,我們經(jīng)常看到下面的函數(shù)用法: with open("test.txt", "w") as f...
    hugoren閱讀 816評(píng)論 0 0
  • 一 裝飾器介紹 1.1 為何要用裝飾器 軟件的設(shè)計(jì)應(yīng)該遵循開放封閉原則,即對(duì)擴(kuò)展是開放的榜掌,而對(duì)修改是封閉的优妙。對(duì)擴(kuò)展...
    100斤的瘦子_湯勇閱讀 566評(píng)論 0 0
  • 表情是什么,我認(rèn)為表情就是表現(xiàn)出來的情緒憎账。表情可以傳達(dá)很多信息套硼。高興了當(dāng)然就笑了,難過就哭了胞皱。兩者是相互影響密不可...
    Persistenc_6aea閱讀 124,544評(píng)論 2 7