您好,登錄后才能下訂單哦!
本文實例講述了python 自定義裝飾器。分享給大家供大家參考,具體如下:
先看一個例子
def deco(func): print("before myfunc() called.") func() print("after myfunc() called.") return func @deco def myfunc(): print("myfunc() called.") # myfunc = deco(myfunc) # 與上面的@deco等價 myfunc() print("***********") myfunc()
會發現,輸出為
before myfunc() called.
myfunc() called.
after myfunc() called.
myfunc() called.
***********
myfunc() called.
這就是說,裝飾器里面的東西只調用了一次,為什么呢?
是因為,在myfunc()函數的定義前面加一句@deco,本質上完全等價于在出現def myfunc()后,先將下面所有內容的首地址傳遞給func,然后緊接著加上一句 myfunc = deco(myfunc)。執行這句話,表示func代表了本來定義的myfunc()的函數體,同時函數myfunc()的地址傳遞給deco()函數,即 myfunc -> func,這里就相當于myfunc的值與func的值完全相同了。然后執行裝飾器里面的內容,最后返回給func,傳遞給myfunc。接下來在調用myfunc()的時候,打印輸出“myfunc() called”。第二次調用myfunc()函數的時候,依然只打印輸出“myfunc() called”。為什么第二次沒有執行裝飾器里面的內容呢?是因為,myfunc = deco(myfunc)這句話只執行了一次,而這句話,才是真正執行裝飾器里面的內容的話。
上面的代碼表示,裝飾器相當于只對第一次調用他的函數進行了裝飾,那么,怎么對每次調用的函數都裝飾呢?接著看
def deco(func): def wrapper(*args, **kwargs): # *args, **kwargs用于接收func的參數 print("before myfunc() called.") func(*args, **kwargs) print("after myfunc() called.") return wrapper @deco def myfunc(a, b): print(a+b) # myfunc = deco(myfunc) # 與上面的@deco等價 myfunc(1, 2) print("***********") myfunc(3, 4)
該代碼輸出結果為
before myfunc() called.
3
after myfunc() called.
***********
before myfunc() called.
7
after myfunc() called.
我們說了,在myfunc()函數的定義前面加一句@deco,本質上完全等價于在出現def?myfunc()后,先將下面所有內容的首地址傳遞給func,然后緊接著加上一句 myfunc = deco(myfunc)。執行myfunc(1, 2)命令的時候,myfunc函數體的地址早已經傳遞給了deco()函數,返回的是wrapper。這是myfunc所代表的地址不再是原來的myfunc的地址,而是wrapper函數的地址。所以,以后凡是出現myfunc()的地方,都是在調用wrapper()函數。即myfunc(1, 2)就是wrapper(1, 2),所以每次調用myfunc()時候,裝飾器里面的內容都會被執行了。而wrapper()函數體里面的func,就代表了原來myfunc()的函數體。
怎么進一步理解“在出現def?myfunc()后,先將下面所有內容的首地址傳遞給func”這句話呢?看:
def deco(func): def wrapper(*args, **kwargs): # *args, **kwargs用于接收func的參數 print("wrapper的地址:", wrapper) func(*args, **kwargs) print("func的地址:", func) return wrapper @deco def myfunc(a, b): print("myfunc的地址:",myfunc) print(a+b) # myfunc = deco(myfunc) # 與上面的@deco等價 myfunc(1, 2) print("***********") print("修改后myfunc的地址:",myfunc)
運行結果:
wrapper的地址: <function deco.<locals>.wrapper at 0x0000023AA9FF58C8>
myfunc的地址: <function deco.<locals>.wrapper at 0x0000023AA9FF58C8>
3
func的地址: <function myfunc at 0x0000023AA9FF5840>
***********
修改后myfunc的地址: <function deco.<locals>.wrapper at 0x0000023AA9FF58C8>
程序執行到myfunc(1,2)的時候,本質上是在執行wrapper(1, 2),于是先輸出wrapper的地址,再執行func()函數。執行func()函數的時候,輸出myfunc()的地址,(可見,此時myfunc的值與wrapper的是相等),再打印3。當輸出func()函數的地址,可見func()函數的地址與myfunc()函數的地址不一樣了!!!!這就是說,原來定義的myfunc()函數的函數體,已經屬于func了,而不屬于myfunc了!!
進一步見證奇跡!!
def deco(func): def wrapper(*args, **kwargs): # *args, **kwargs用于接收func的參數 pass return wrapper @deco def myfunc(a, b): print(a+b) myfunc(1, 2)
該代碼沒有任何輸出。那是因為,執行myfunc(1, 2)的時候,本質上是執行wrapper(1, 2)。而wrapper(1, 2)又不干任何事情,所以沒有輸出。至于print(a+b)這句話,他的地址已經屬于func了。
帶參數的裝飾器,可以參見其他文章
更多關于Python相關內容可查看本站專題:《Python數據結構與算法教程》、《Python Socket編程技巧總結》、《Python函數使用技巧總結》、《Python字符串操作技巧匯總》及《Python入門與進階經典教程》
希望本文所述對大家Python程序設計有所幫助。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。