python 自定義裝飾器實(shí)例詳解
本文實(shí)例講述了python 自定義裝飾器。分享給大家供大家參考,具體如下:
先看一個(gè)例子
def deco(func): print("before myfunc() called.") func() print("after myfunc() called.") return func @deco def myfunc(): print("myfunc() called.") # myfunc = deco(myfunc) # 與上面的@deco等價(jià) myfunc() print("***********") myfunc()
會(huì)發(fā)現(xiàn),輸出為
before myfunc() called.
myfunc() called.
after myfunc() called.
myfunc() called.
***********
myfunc() called.
這就是說(shuō),裝飾器里面的東西只調(diào)用了一次,為什么呢?
是因?yàn)?,在myfunc()函數(shù)的定義前面加一句@deco,本質(zhì)上完全等價(jià)于在出現(xiàn)def myfunc()后,先將下面所有內(nèi)容的首地址傳遞給func,然后緊接著加上一句 myfunc = deco(myfunc)。執(zhí)行這句話,表示func代表了本來(lái)定義的myfunc()的函數(shù)體,同時(shí)函數(shù)myfunc()的地址傳遞給deco()函數(shù),即 myfunc -> func,這里就相當(dāng)于myfunc的值與func的值完全相同了。然后執(zhí)行裝飾器里面的內(nèi)容,最后返回給func,傳遞給myfunc。接下來(lái)在調(diào)用myfunc()的時(shí)候,打印輸出“myfunc() called”。第二次調(diào)用myfunc()函數(shù)的時(shí)候,依然只打印輸出“myfunc() called”。為什么第二次沒有執(zhí)行裝飾器里面的內(nèi)容呢?是因?yàn)?,myfunc = deco(myfunc)這句話只執(zhí)行了一次,而這句話,才是真正執(zhí)行裝飾器里面的內(nèi)容的話。
上面的代碼表示,裝飾器相當(dāng)于只對(duì)第一次調(diào)用他的函數(shù)進(jìn)行了裝飾,那么,怎么對(duì)每次調(diào)用的函數(shù)都裝飾呢?接著看
def deco(func): def wrapper(*args, **kwargs): # *args, **kwargs用于接收f(shuō)unc的參數(shù) 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等價(jià) myfunc(1, 2) print("***********") myfunc(3, 4)
該代碼輸出結(jié)果為
before myfunc() called.
3
after myfunc() called.
***********
before myfunc() called.
7
after myfunc() called.
我們說(shuō)了,在myfunc()函數(shù)的定義前面加一句@deco,本質(zhì)上完全等價(jià)于在出現(xiàn)def?myfunc()后,先將下面所有內(nèi)容的首地址傳遞給func,然后緊接著加上一句 myfunc = deco(myfunc)。執(zhí)行myfunc(1, 2)命令的時(shí)候,myfunc函數(shù)體的地址早已經(jīng)傳遞給了deco()函數(shù),返回的是wrapper。這是myfunc所代表的地址不再是原來(lái)的myfunc的地址,而是wrapper函數(shù)的地址。所以,以后凡是出現(xiàn)myfunc()的地方,都是在調(diào)用wrapper()函數(shù)。即myfunc(1, 2)就是wrapper(1, 2),所以每次調(diào)用myfunc()時(shí)候,裝飾器里面的內(nèi)容都會(huì)被執(zhí)行了。而wrapper()函數(shù)體里面的func,就代表了原來(lái)myfunc()的函數(shù)體。
怎么進(jìn)一步理解“在出現(xiàn)def?myfunc()后,先將下面所有內(nèi)容的首地址傳遞給func”這句話呢?看:
def deco(func): def wrapper(*args, **kwargs): # *args, **kwargs用于接收f(shuō)unc的參數(shù) 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等價(jià) myfunc(1, 2) print("***********") print("修改后myfunc的地址:",myfunc)
運(yùn)行結(jié)果:
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>
程序執(zhí)行到myfunc(1,2)的時(shí)候,本質(zhì)上是在執(zhí)行wrapper(1, 2),于是先輸出wrapper的地址,再執(zhí)行func()函數(shù)。執(zhí)行func()函數(shù)的時(shí)候,輸出myfunc()的地址,(可見,此時(shí)myfunc的值與wrapper的是相等),再打印3。當(dāng)輸出func()函數(shù)的地址,可見func()函數(shù)的地址與myfunc()函數(shù)的地址不一樣了?。。?!這就是說(shuō),原來(lái)定義的myfunc()函數(shù)的函數(shù)體,已經(jīng)屬于func了,而不屬于myfunc了!!
進(jìn)一步見證奇跡??!
def deco(func): def wrapper(*args, **kwargs): # *args, **kwargs用于接收f(shuō)unc的參數(shù) pass return wrapper @deco def myfunc(a, b): print(a+b) myfunc(1, 2)
該代碼沒有任何輸出。那是因?yàn)?,?zhí)行myfunc(1, 2)的時(shí)候,本質(zhì)上是執(zhí)行wrapper(1, 2)。而wrapper(1, 2)又不干任何事情,所以沒有輸出。至于print(a+b)這句話,他的地址已經(jīng)屬于func了。
帶參數(shù)的裝飾器,可以參見其他文章
更多關(guān)于Python相關(guān)內(nèi)容可查看本站專題:《Python數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Python Socket編程技巧總結(jié)》、《Python函數(shù)使用技巧總結(jié)》、《Python字符串操作技巧匯總》及《Python入門與進(jìn)階經(jīng)典教程》
希望本文所述對(duì)大家Python程序設(shè)計(jì)有所幫助。
相關(guān)文章
對(duì)python中array.sum(axis=?)的用法介紹
今天小編就為大家分享一篇對(duì)python中array.sum(axis=?)的用法介紹,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-06-06Python基礎(chǔ)進(jìn)階之海量表情包多線程爬蟲功能的實(shí)現(xiàn)
這篇文章主要介紹了Python基礎(chǔ)進(jìn)階之海量表情包多線程爬蟲,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12這三個(gè)好用的python函數(shù)你不能不知道!
作為21世紀(jì)最流行的語(yǔ)言之一,Python當(dāng)然有很多有趣的功能值得深入探索和研究.今天通過(guò)理論和實(shí)際例子來(lái)討論,需要的朋友可以參考下2021-06-06Python中字符串轉(zhuǎn)換為列表的常用方法總結(jié)
本文將詳細(xì)介紹Python中將字符串轉(zhuǎn)換為列表的八種常用方法,每種方法都具有其獨(dú)特的用途和適用場(chǎng)景,文中的示例代碼講解詳細(xì),感興趣的可以了解下2023-11-11對(duì)Python3中列表乘以某一個(gè)數(shù)的示例詳解
今天小編就為大家分享一篇對(duì)Python3中列表乘以某一個(gè)數(shù)的示例詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-07-07Python類繼承及super()函數(shù)使用說(shuō)明
這篇文章主要介紹了Python類繼承及super()函數(shù)使用說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11