函數(shù)裝飾器

裝飾器基礎(chǔ)知識

裝飾器是可調(diào)用的對象葫督,其參數(shù)是另一個函數(shù)(被裝飾的函數(shù))。裝飾器可能會處理被裝飾的函數(shù)斜筐,然后把它返回冰啃,或者將其替換成另一個函數(shù)或可調(diào)用對象邓夕。

假如有個名為decorate的裝飾器:

@decorate

def target():

? ? print('running target()')

上述代碼的效果與下述寫法一樣:

def target():

? ? print('running target()')

target=decorate(target)

這兩種寫法的最終結(jié)果一樣:上述兩個代碼片段執(zhí)行完畢后得到的target不一定是原來那個target函數(shù),而是decorate(target)返回的函數(shù)亿笤。

python何時執(zhí)行裝飾器

裝飾器的一個關(guān)鍵特性是翎迁,它們在被裝飾的函數(shù)定義之后立即運行栋猖,這通常是在導(dǎo)入(即python加載模塊時)

上述腳本運行得到的輸出如下:


上述示例主要想強調(diào)净薛,函數(shù)裝飾器在導(dǎo)入模塊時立即執(zhí)行,而被裝飾的函數(shù)只在明確調(diào)用時運行蒲拉,考慮到裝飾器在真實代碼中的常用調(diào)用方式肃拜,上述示例有兩個不尋常的地方:

1、裝飾器函數(shù)與被裝飾的函數(shù)在同一個模塊中定義雌团。實際情況是燃领,裝飾器常在一個模塊中定義,然后應(yīng)用到其他模塊的函數(shù)中锦援。

2猛蔽、registry裝飾器返回的函數(shù)與通過參數(shù)傳入的相同。實際上灵寺,大多數(shù)裝飾器會在內(nèi)部定義一個函數(shù)曼库,然后將其返回。

變量的作用域規(guī)則

例:一個函數(shù)略板,讀取一個局部變量和一個全局變量


在上述例子中毁枯,python在編譯函數(shù)的定義體時,它判斷b是局部變量叮称,因為在函數(shù)中給它賦值了种玛,python會嘗試從本地環(huán)境獲取b藐鹤。后面調(diào)用f2(3)時,f2的定義體會獲取并打印局部變量a的值赂韵,但是嘗試獲取局部變量b時娱节,發(fā)現(xiàn)b沒有綁定值

實現(xiàn)一個簡單的裝飾器

下例定義了一個裝飾器,它會在每次調(diào)用被裝飾的函數(shù)時計時祭示,然后把經(jīng)過的時間括堤、傳入的參數(shù)和調(diào)用的結(jié)果打印出來。

使用clock裝飾器


上述例子中實現(xiàn)的clock裝飾器有幾個缺點:不支持關(guān)鍵字參數(shù)绍移,而且遮蓋了被裝飾函數(shù)的__name__和__doc__屬性悄窃。下述例子使用functools.wraps裝飾器把相關(guān)的屬性從func復(fù)制到clocked中。

參數(shù)化裝飾器

解析源碼中的裝飾器時蹂窖,python把被裝飾的函數(shù)作為第一個參數(shù)傳給裝飾器函數(shù)轧抗。那怎么讓裝飾器接受其他參數(shù)呢?答案是:創(chuàng)建一個裝飾器工廠函數(shù)瞬测,把參數(shù)傳給它横媚,返回一個裝飾器,然后再把它應(yīng)用到要裝飾的函數(shù)上月趟。

為了便于啟用或禁用register執(zhí)行的函數(shù)注冊功能灯蝴,我們?yōu)樗峁┮粋€可選的active參數(shù),設(shè)為false時孝宗,不注冊被裝飾的函數(shù)穷躁,示例如下,從概念上看因妇,這個新的register函數(shù)不是裝飾器问潭,而是裝飾器工廠函數(shù)。調(diào)用它會返回真正的裝飾器婚被,這才是應(yīng)用到目標函數(shù)上的裝飾器狡忙。


在上述例子中:

1、registry是一個set對象址芯,這樣添加和刪除函數(shù)的速度更快灾茁。

2、register接受一個可選的關(guān)鍵字參數(shù)谷炸。

3北专、decorate這個內(nèi)部函數(shù)是真正的裝飾器,它的參數(shù)是一個函數(shù)淑廊。

4逗余、decorate是裝飾器,必須返回一個函數(shù)季惩。

5录粱、register是裝飾器工廠函數(shù)腻格,因此返回decorate。

6啥繁、register是裝飾器工廠函數(shù)菜职,因此返回decorate。

7旗闽、@register工廠函數(shù)必須作為函數(shù)調(diào)用酬核,并且傳入所需的函數(shù)。

這里的關(guān)鍵是适室,register()要返回decorate嫡意,然后把它應(yīng)用到被裝飾的函數(shù)上。

參數(shù)化clock裝飾器


在上述示例中:

1捣辆、clock是參數(shù)化裝飾器工廠函數(shù)蔬螟。

2、decorate是真正的裝飾器汽畴。

3旧巾、clocked包裝被裝飾的函數(shù)。

4忍些、這里使用**locals()是為了在fmt中引用clocked的局部變量鲁猩。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市罢坝,隨后出現(xiàn)的幾起案子廓握,更是在濱河造成了極大的恐慌,老刑警劉巖炸客,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疾棵,死亡現(xiàn)場離奇詭異戈钢,居然都是意外死亡痹仙,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門殉了,熙熙樓的掌柜王于貴愁眉苦臉地迎上來开仰,“玉大人,你說我怎么就攤上這事薪铜≈诠” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵隔箍,是天一觀的道長谓娃。 經(jīng)常有香客問我,道長蜒滩,這世上最難降的妖魔是什么滨达? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任奶稠,我火速辦了婚禮,結(jié)果婚禮上捡遍,老公的妹妹穿的比我還像新娘锌订。我一直安慰自己,他們只是感情好画株,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布辆飘。 她就那樣靜靜地躺著,像睡著了一般谓传。 火紅的嫁衣襯著肌膚如雪蜈项。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天续挟,我揣著相機與錄音战得,去河邊找鬼。 笑死庸推,一個胖子當著我的面吹牛常侦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播贬媒,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼聋亡,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了际乘?” 一聲冷哼從身側(cè)響起坡倔,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎脖含,沒想到半個月后罪塔,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡养葵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年征堪,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片关拒。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡佃蚜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出着绊,到底是詐尸還是另有隱情谐算,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布归露,位于F島的核電站洲脂,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏剧包。R本人自食惡果不足惜恐锦,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一雇毫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧踩蔚,春花似錦棚放、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至福也,卻和暖如春局骤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背暴凑。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工峦甩, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人现喳。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓凯傲,卻偏偏與公主長得像,于是被迫代替她去往敵國和親嗦篱。 傳聞我的和親對象是個殘疾皇子冰单,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

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