python装饰器源代码_13-Python-装饰器
1、裝飾器的定義
裝飾器的本質(zhì)就是函數(shù),用來(lái)裝飾其它函數(shù),就是為其它函數(shù)添加附加功能。
裝飾器原則如下:
不能修改被裝飾的函數(shù)的源代碼
不能修改被裝飾的函數(shù)的調(diào)用方式
2、實(shí)現(xiàn)裝飾器知識(shí)儲(chǔ)備
函數(shù)即變量
1 defbar():2 print("in the bar")3 deffoo():4 print("in the foo")5 bar()6
7 foo()8
9 print("----------分割線-----------")10
11 deffoo1():12 print("in the foo")13 bar1()14 defbar1():15 print("in the bar")16
17 foo1()18
19 print("----------分割線-----------")20 #這樣會(huì)報(bào)錯(cuò)
21 #def foo2():
22 #print("in the foo")
23 #bar2()
24 #foo2()
25 #def bar2():
26 #print("in the bar")
高階函數(shù)
把一個(gè)函數(shù)名當(dāng)作實(shí)參傳遞給另外一個(gè)函數(shù)(在不修改被裝飾函數(shù)源代碼的情況下為其添加功能)
1 importtime2
3 defbar1():4 time.sleep(3)5 print("in the bar")6
7 deftest2(func):8 start_time =time.time()9 func() #相當(dāng)于運(yùn)行bar1()
10 stop_time =time.time()11 print("total run time %s" %(stop_time -start_time))12
13 test2(bar1)
返回值中包含函數(shù)名(不能修改函數(shù)的調(diào)用方式)
1 defbar2():2 time.sleep(3)3 print("in the bar2")4
5 deftest3(func):6 print(func)7 returnfunc8
9 print(test3(bar2)) #獲取的是內(nèi)存地址
10
11 res =test3(bar2)12 res()
嵌套函數(shù)
1 deffoo():2 print("in the foo")3 defbar():4 print("in the bar")5 bar() #局部變量只能在其作用域內(nèi)調(diào)用
6
7 foo()
1 x =02 defgrandpa():3 x = 1
4 defdad():5 x = 2
6 defson():7 x = 3
8 print(x) #最終打印結(jié)果為3
9 son()10 dad()11 grandpa()
高階函數(shù) + 嵌套函數(shù) --》裝飾器
1 importtime2
3
4 deftimer(func):5 defdeco():6 start_time =time.time()7 func()8 stop_time =time.time()9 print("total time is %s" % (stop_time -start_time))10 return deco #返回deco()的內(nèi)存地址
11
12
13 deftest1():14 time.sleep(3)15 print("in the test1")16
17
18 deftest2():19 time.sleep(3)20 print("in the test2")21
22 #以下可直接用裝飾器語(yǔ)法代替
23 timer(test1) #test1的內(nèi)存地址賦值給func,返回deco()的內(nèi)存地址
24 print(timer(test1)) #返回deco()的內(nèi)存地址
25 test1 = timer(test1) #內(nèi)存地址賦值給test1
26 test1() #相當(dāng)于執(zhí)行deco()
27
28 timer(test2)29 test2 =timer(test2)30 test2()31
32 print("---------我是分隔符---------")33
34
35 #裝飾器語(yǔ)法如下。(和上面引用的效果一樣)
36 @timer #相當(dāng)于test1 = timer(test1)
37 deftest1():38 time.sleep(3)39 print("in the test1")40
41
42 @timer #相當(dāng)于test1 = timer(test1)43 deftest2():44 time.sleep(3)45 print("in the test2")46
47
48 test1()49 test2()
3、動(dòng)態(tài)參數(shù)裝飾器
deftimer(bar):def inner(*args, **kwargs):
start_time=time.time()
foo_ret= bar(*args, **kwargs)
end_time=time.time()
used_time= end_time -start_timeprint(used_time)returnfoo_retreturninner
@timerdef foo(*args, **kwargs):
time.sleep(1)print("我的參數(shù):", args, kwargs)print("我的運(yùn)行時(shí)間:")return "我的返回值"ret= foo("動(dòng)態(tài)參數(shù)裝飾器", (1, 2), name="Druid", age=18)print(ret)
輸出結(jié)果如下:
4、裝飾器原理圖解
4.1 被裝飾函數(shù)沒(méi)有返回值
4.2 被裝飾函數(shù)有返回值
注意:第二步僅為過(guò)程分析量,不作為真實(shí)的執(zhí)行順序。
5、裝飾器固定格式
裝飾器的固定格式如下例所示:
defwrapper(func):"""該函數(shù)為裝飾器函數(shù)
:param func: 這里的func參數(shù)實(shí)質(zhì)是指向被裝飾函數(shù)的內(nèi)存地址
:return:"""
def inner(*args, **kwargs):"""該函數(shù)為裝飾器函數(shù)內(nèi)部函數(shù)
:param args: 實(shí)質(zhì)接收的是被裝飾函數(shù)的位置參數(shù)
:param kwargs: 實(shí)質(zhì)接收的是被裝飾函數(shù)的關(guān)鍵字參數(shù)
:return: 返回的是被裝飾函數(shù)的返回值"""
print("這里放被裝飾函數(shù)執(zhí)行之前要做的事")
func_ret= func(*args, **kwargs) #被裝飾的函數(shù)
print("這里放被裝飾函數(shù)執(zhí)行之后要做的事")returnfunc_retreturninner
@wrapper#等價(jià)于my_func = wrapper(my_func)
def my_func(*args, **kwargs):"""該函數(shù)為被裝飾函數(shù)
:param args: 接收位置參數(shù)
:param kwargs: 接收關(guān)鍵字參數(shù)
:return: 返回值"""
print(*args, **kwargs)returnret
ret= my_func() #執(zhí)行原函數(shù),實(shí)質(zhì)是執(zhí)行inner()。函數(shù)返回值保存在變量ret中。
6、裝飾器修復(fù)
當(dāng)我們使用裝飾器去裝飾某個(gè)函數(shù)時(shí),我們想要引用被裝飾函數(shù)原私有屬性,如__name__、__doc__時(shí),就有問(wèn)題了,因?yàn)槲覀冸m然仍然在執(zhí)行被裝飾函數(shù),但其實(shí)執(zhí)行的是閉包,看下例。
defwrapper(func):"""該函數(shù)為裝飾器函數(shù)
:param func: 這里的func參數(shù)實(shí)質(zhì)是指向被裝飾函數(shù)的內(nèi)存地址
:return:"""
def inner(*args, **kwargs):"""該函數(shù)為閉包(裝飾器函數(shù)內(nèi)部函數(shù))
:param args: 實(shí)質(zhì)接收的是被裝飾函數(shù)的位置參數(shù)
:param kwargs: 實(shí)質(zhì)接收的是被裝飾函數(shù)的關(guān)鍵字參數(shù)
:return: 返回的是被裝飾函數(shù)的返回值"""func_ret= func(*args, **kwargs) #被裝飾的函數(shù)
returnfunc_retreturninner
@wrapper#等價(jià)于my_func = wrapper(my_func)
def my_func(*args, **kwargs):"""該函數(shù)為被裝飾函數(shù)
:param args: 接收位置參數(shù)
:param kwargs: 接收關(guān)鍵字參數(shù)
:return: 返回值"""
print(*args, **kwargs)return "返回值"my_func("裝飾器沒(méi)被修復(fù)前,被裝飾函數(shù)原函數(shù)的私有屬性如__name__、__doc__是獲取不到的,如下:") #執(zhí)行原函數(shù),實(shí)質(zhì)是執(zhí)行inner()
print(my_func.__name__) #打印函數(shù)的名字
print(my_func.__doc__) #打印函數(shù)的注釋文檔
輸出結(jié)果如下:
如果仍想使用被裝飾函數(shù)的原私有屬性,那么就可以用裝飾器修復(fù):
from functools importwrapsdefwrapper(func):"""該函數(shù)為裝飾器函數(shù)
:param func: 這里的func參數(shù)實(shí)質(zhì)是指向被裝飾函數(shù)的內(nèi)存地址
:return:"""@wraps(func)def inner(*args, **kwargs):"""該函數(shù)為閉包(裝飾器函數(shù)內(nèi)部函數(shù))
:param args: 實(shí)質(zhì)接收的是被裝飾函數(shù)的位置參數(shù)
:param kwargs: 實(shí)質(zhì)接收的是被裝飾函數(shù)的關(guān)鍵字參數(shù)
:return: 返回的是被裝飾函數(shù)的返回值"""func_ret= func(*args, **kwargs) #被裝飾的函數(shù)
print("裝飾器修復(fù)不會(huì)改變?cè)b飾器的作用")returnfunc_retreturninner
@wrapper#等價(jià)于my_func = wrapper(my_func)
def my_func(*args, **kwargs):"""該函數(shù)為被裝飾函數(shù)
:param args: 接收位置參數(shù)
:param kwargs: 接收關(guān)鍵字參數(shù)
:return: 返回值"""
print(*args, **kwargs)return "返回值"my_func("裝飾器被修復(fù)后,被裝飾函數(shù)原函數(shù)的私有屬性如__name__、__doc__就可以正常獲取了,如下:") #執(zhí)行原函數(shù),實(shí)質(zhì)是執(zhí)行inner()
print(my_func.__name__) #打印函數(shù)的名字
print(my_func.__doc__) #打印函數(shù)的注釋文檔
輸出結(jié)果如下:
7、帶參數(shù)的裝飾器
需求:很多函數(shù)共用一個(gè)裝飾器,要求隨時(shí)可以關(guān)閉裝飾器功能,且盡可能的減少代碼修改。 該需求可以用標(biāo)記位來(lái)實(shí)現(xiàn),如下:
importtime
FLAG=Truedeftimmer_out(flag):deftimmer(func):def inner(*args, **kwargs):ifflag:
start_time=time.time()
ret_func= func(*args, **kwargs)
end_time=time.time()
used_time= end_time -start_timeprint("函數(shù){name}執(zhí)行時(shí)間:{time}".format(name=func.__name__, time=used_time))#print("函數(shù){name}執(zhí)行時(shí)間:{time}".format_map({"name": func.__name__, "time": used_time}))
else:
ret_func= func(*args, **kwargs)returnret_funcreturninnerreturntimmer
@timmer_out(FLAG)#第一步,先執(zhí)行timmer_out(FLAG),得到返回值timmer。第二步執(zhí)行@timmer,即 my_func1 = timmer(my_func1)
defmy_func1():
time.sleep(1)print("my_func1")
@timmer_out(FLAG)defmy_func2():
time.sleep(1)print("my_func2")
@timmer_out(FLAG)defmy_func3():
time.sleep(1)print("my_func3")
my_func1()
my_func2()
my_func3()
當(dāng)FLAG置為T(mén)rue時(shí),裝飾器功能生效,輸出結(jié)果如下圖所示:
當(dāng)FLAG置為False時(shí),裝飾器功能關(guān)閉,輸出結(jié)果如下圖所示:
8、多個(gè)裝飾器裝飾一個(gè)函數(shù)
defwrapper1(func):definner1():print("wrapper1, before func")
func()print("wrapper1, after func")returninner1defwrapper2(func):definner2():print("wrapper2, before func")
func()print("wrapper2, after func")returninner2
@wrapper2
@wrapper1defmy_func():print("function is my func")
my_func()
注意輸出結(jié)果:
為什么結(jié)果是這樣?請(qǐng)看如下分析:
為什么是先執(zhí)行@wrapper1而不是@wrapeer2呢?因?yàn)檠b飾器在找到被裝飾函數(shù)會(huì)優(yōu)先執(zhí)行。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的python装饰器源代码_13-Python-装饰器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 时代长安标准电芯正式下线,20%-80%
- 下一篇: python大鱼吃小鱼_python 游