python编写装饰器_我也来写一下python装饰器
有借用,但原文出處已經(jīng)找不到了,根據(jù)筆記分享一下解釋器的基礎(chǔ)。
下面的代碼表示,等待兩秒鐘,輸出‘test is running'。
現(xiàn)在要求增加統(tǒng)計(jì)程序運(yùn)行時(shí)間的功能。
等待兩秒鐘,輸出‘test is running',現(xiàn)要求增加統(tǒng)計(jì)程序運(yùn)行時(shí)間的功能。
import time
def test():
time.sleep(2)
print('test is running!')
test()
學(xué)習(xí)先問(wèn)為什么,有什么用,學(xué)基礎(chǔ)的時(shí)候有時(shí)不理解為什么簡(jiǎn)單的事情要搞那么復(fù)雜,而對(duì)應(yīng)的實(shí)際應(yīng)用時(shí),往往“這個(gè)復(fù)雜方法有很多優(yōu)點(diǎn)和簡(jiǎn)化了很多事情”。學(xué)基礎(chǔ)時(shí)用簡(jiǎn)單的例子,只是為了講明知識(shí)點(diǎn),而不要去關(guān)注例子實(shí)現(xiàn)的什么功能,這個(gè)功能當(dāng)然是個(gè)‘屁’了。
那么,裝飾器的實(shí)際應(yīng)用場(chǎng)景:程序已上線或已使用,但需要增加新功能,修改原函數(shù)不合理也不科學(xué)(這里真的包含了很多背景聲音),就要求:
(1)不能修改原功能函數(shù)的代碼。例子中的功能是非常簡(jiǎn)單的,要實(shí)現(xiàn)當(dāng)然是直接修改,但現(xiàn)實(shí)中一個(gè)功能的實(shí)現(xiàn)是非常復(fù)雜的代碼,直接修改是不合理不科學(xué)的。
(2)不能修改原函數(shù)的調(diào)用方式。在符合第一條的情況下,調(diào)用時(shí)仍然是用test(),即老方法能實(shí)現(xiàn)新功能。現(xiàn)實(shí)中后面程序在反復(fù)用test(),就是要完全不動(dòng)老代碼的基礎(chǔ)上,增加一個(gè)’裝飾器‘更新整個(gè)程序。
(3)上述說(shuō)的老方法是表面上的,這就是裝飾器介入的作用。
好,以下開(kāi)始改造,用試錯(cuò)的方法解釋裝飾器的實(shí)現(xiàn)過(guò)程和原理。
滿足條件(1)可以增加代碼如下:
def deco(func):
start=time.time()
func()
stop=time.time()
print(stop-start)
deco(test)
#把老代碼里的test函數(shù)作為參數(shù)傳遞給新函數(shù)
#(因?yàn)槭窃黾有鹿δ?#xff0c;老功能還是要的,所以新代碼里肯定要引用老代碼的功能,就采取了這種方法)
看上去新功能就實(shí)現(xiàn)了,但可以看到調(diào)用方式變?yōu)榱薲eco(test),即違背了條件(2),以前程序里可能反復(fù)調(diào)用了test(),都要改成deco(test),不科學(xué)。
同時(shí)滿足條件(2),再改:
思路:產(chǎn)生一個(gè)新函數(shù),重新賦值給test,test=某函數(shù),那么后面反復(fù)調(diào)用的test()就被實(shí)質(zhì)上改過(guò)來(lái)了,實(shí)現(xiàn)功能。
#試一下:
test=deco(test) #計(jì)算右邊的,是一個(gè)兩行字符串,賦值給test根本不是一個(gè)函數(shù)。
test() #因此跳錯(cuò)誤碼
再試一下:
增加:return func
然后:
test=deco(test)
test()
代碼正常運(yùn)行,但因?yàn)閞eturn func的縮進(jìn)和其他代碼是同級(jí)的,所以deco(test)這步已經(jīng)把新功能給實(shí)現(xiàn)了,又返回了一次test(),結(jié)果重復(fù)。
把下面完整的代碼去試一下,出現(xiàn)了兩次test is running ,不合格。
import time
def test():
time.sleep(2)
print('test is running!')
def deco(func):
start=time.time()
func()
stop=time.time()
print(stop-start)
return func
test=deco(test)
test()
思路沒(méi)有錯(cuò),上述這里return一個(gè)函數(shù)的思考過(guò)程也是對(duì)的,只是返回的方式不對(duì),應(yīng)當(dāng)使用’嵌套函數(shù)‘。
def timer(func):
def deco():
start=time.time()
func()
stop=time.time()
print(stop-start)
return deco
#把deco()嵌套在timer(func)里,返回一個(gè)deco()函數(shù)的函數(shù)名deco;
#調(diào)用timer(func)時(shí),deco()里面的過(guò)程代碼類(lèi)似于沒(méi)有執(zhí)行的,
#被打包成了一個(gè)函數(shù),執(zhí)行的只是return了這個(gè)函數(shù)的函數(shù)名。
test=timer(test)
#右邊代碼返回的是一個(gè)deco()的函數(shù)名deco,deco()打包了作為被參數(shù)傳入的原test()里的功能,
#同時(shí)增加了新功能。
test()
#符合(2)要求,沒(méi)有改變調(diào)用方法,但實(shí)質(zhì)上這句調(diào)用的已經(jīng)是deco()了。
#頂格代碼是不能調(diào)用經(jīng)過(guò)了二次縮進(jìn)的嵌套函數(shù)的,
#但這里用了deco()用了return,成了閉包函數(shù),就可以被調(diào)用了。
至此,本質(zhì)上是修改了調(diào)用函數(shù),但在表面上并未修改調(diào)用方式,而且實(shí)現(xiàn)了附加功能,需求實(shí)現(xiàn)。
真正的裝飾器:語(yǔ)法糖
在原test()的上一行加上@timer,刪除test=timer(test).
而且要把新增的函數(shù)寫(xiě)在原函數(shù)的上面
最后代碼
import time
def timer(func):
print(func.__name__) #看看打印出來(lái)的是什么
def deco():
start=time.time()
func()
stop=time.time()
print(stop-start)
return deco
@timer
def test():
time.sleep(2)
print('test is running')
#test=timer(test)這句不用了,注釋掉
test()
過(guò)程比較啰嗦,但每一步都看下來(lái)后,裝飾 器的原理就知道了,涉及到有參數(shù)的時(shí)候,再另外理解了。
總結(jié)
以上是生活随笔為你收集整理的python编写装饰器_我也来写一下python装饰器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 手写springboot_Spring
- 下一篇: python实例化对象做实参_如何在Py