python裝飾器 原來如此簡單

2021-07-26 19:29:20 字數 3173 閱讀 3739

今天整理裝飾器,內嵌的裝飾器、讓裝飾器帶引數等多種形式,非常複雜,讓人頭疼不已。但是突然間發現了裝飾器的奧秘,原來如此簡單。。。。

# -*- coding:gbk -*-

'''示例1: 使用語法糖@來裝飾函式,相當於「myfunc = deco(myfunc)」

但發現新函式只在第一次被呼叫,且原函式多呼叫了一次'''

defdeco

(func):

print("before myfunc() called.")

func()

print(" after myfunc() called.")

return func

@deco

defmyfunc

(): print(" myfunc() called.")

myfunc()

myfunc()

這是乙個最簡單的裝飾器的例子,但是這裡有乙個問題,就是當我們兩次呼叫myfunc()的時候,發現裝飾器函式只被呼叫了一次。為什麼會這樣呢?要解釋這個就要給出破解裝飾器的關鍵鑰匙了。

這裡@deco這一句,和myfunc = deco(myfunc)其實是完全等價的,只不過是換了一種寫法而已

一定要記住上面這句!!!!

好了,從現在開始,只需要做替換操作就可以了。

將@deco 替換為 myfunc = deco(myfunc)

程式首先呼叫deco(myfunc),得到的返回結果賦值給了myfunc (注意:在python中函式名只是個指向函式首位址的函式指標而已)

而deco(myfunc)的返回值就是函式myfunc()的位址

這樣其實myfunc 沒有變化,也就是說,最後的兩次myfunc()函式呼叫,其實都沒有執行到deco()。

有同學就問了,明明列印了deco()函式裡面的內容啊,怎麼說沒有呼叫到呢。這位同學一看就是沒有注意聽講,那一次列印是在@deco 這一句被執行的。大家親自動手試一下就會發現」 myfunc() called.」 這句列印輸出了三次。多的那次就是@deco這裡輸出的,因為@deco 等價於myfunc = deco(myfunc),這裡已經呼叫了deco()函式了。

怎麼解決裝飾器沒有被呼叫的問題呢

# -*- coding:gbk -*-

'''示例2: 使用內嵌包裝函式來確保每次新函式都被呼叫,

內嵌包裝函式的形參和返回值與原函式相同,裝飾函式返回內嵌包裝函式物件'''

defdeco

(func):

def_deco

(): print("before myfunc() called.")

func()

print(" after myfunc() called.")

# 不需要返回func,實際上應返回原函式的返回值

return _deco

@deco

defmyfunc

(): print(" myfunc() called.")

return

'ok'

myfunc()

myfunc()

這裡其實不需要我解釋了,還是按照第一步中的方法做替換就可以了。還是囉嗦幾句吧。。

@deco 替換為 myfunc = deco(myfunc)

程式首先呼叫deco(myfunc),得到的返回結果賦值給了myfunc ,這樣myfunc 就變成了指向函式_deco()的指標

以後的myfunc(),其實是呼叫_deco()

破案過程和第一步、第二步完全一致,不再重複了

# -*- coding:gbk -*-

'''示例5: 對帶引數的函式進行裝飾,

內嵌包裝函式的形參和返回值與原函式相同,裝飾函式返回內嵌包裝函式物件'''

defdeco

(func):

def_deco

(a, b):

print("before myfunc() called.")

ret = func(a, b)

print(" after myfunc() called. result: %s" % ret)

return ret

return _deco

@deco

defmyfunc

(a, b):

print(" myfunc(%s,%s) called." % (a, b))

return a + b

myfunc(1, 2)

myfunc(3, 4)

# -*- coding:gbk -*-

'''示例7: 在示例4的基礎上,讓裝飾器帶引數,

和上一示例相比在外層多了一層包裝。

裝飾函式名實際上應更有意義些'''

defdeco

(arg):

def_deco

(func):

def__deco

(): print("before %s called [%s]." % (func.__name__, arg))

func()

print(" after %s called [%s]." % (func.__name__, arg))

return __deco

return _deco

@deco("mymodule")

defmyfunc

(): print(" myfunc() called.")

@deco("module2")

defmyfunc2

(): print(" myfunc2() called.")

myfunc()

myfunc2()

這種帶引數的裝飾器怎麼解釋呢。其實是一樣的,還是我們的替換操作

@deco(「mymodule」)替換為myfunc = deco(「mymodule」)(myfunc )

注意啊,這裡deco後面跟了兩個括號。

有同學要問了,這是什麼意思?

其實很簡單,先執行deco(「mymodule」),返回結果為_deco

再執行_deco(myfunc),得到的返回結果為__deco

所以myfunc = __deco

破案!

原來如此簡單

你對我說美麗的女孩子是種危險的動物,她們詭譎善變,揚起貓一樣的觸鬚來挑動你身上的每一處情感神經。不過我想不管是哪種型別的女孩子,在她的心中的某個角落一定藏著乙份對於純美愛情的嚮往,只是表現出來的樣子不同罷了!喜歡彈鋼琴只彈黑鍵,喜歡把熱牛奶放在左邊,喜歡對著毛絨娃娃傾訴我對你的想念。想讓你知道我就是...

理解ERP原來如此簡單

家 中 請 客 訂貨意向 妻子 當然可以,來幾個人,幾點來,想吃什麼菜?丈夫 6個人,我們7點左右回來,準備些酒 烤鴨 番茄炒蛋 冷盤 蛋花湯。你 看可以嗎?商務溝通 妻子 沒問題,我會準備好的,訂單確認 妻子記錄下需要做的選單 mps計畫 具體要準備的菜 鴨 酒 番茄 雞蛋 作 油。bom物料清單...

MS UI Automation原來如此

最近參加了公司的乙個program competition,做個小工具。其中涉及到乙個盲點。需求是 在 中訪問另乙個program的程序,獲取它的視窗控制代碼,並在它的視窗上對某乙個控制項進行滑鼠點選操作以執行相應的命令。google來baidu去,終於有思路了 原來需要用到ms的ui automa...