Decorator
==裝飾器模式==提供在不破壞函數(shù)內(nèi)部結(jié)構(gòu)的前提下動(dòng)態(tài)添加代碼的功能说榆。
舉個(gè)栗子,想要知道一個(gè)函數(shù)在執(zhí)行過程中所耗費(fèi)的時(shí)間寸认。
函數(shù)A
def A(x, y):
time.sleep(1)
print("A")
return x + y
使用裝飾器模式包裝該方法:
def calculateFunTime(fun):
@functools.wraps(fun)
def wraps(*args, **kwargs):
startTime = time.time()
fun(*args, **kwargs)
endTime = time.time()
print("fun %s 執(zhí)行了 %.4f s" % (fun.__name__, endTime - startTime))
return fun
return wraps
如何使用該calculateFunTime方法,只需要在要計(jì)算的方法頭加上<font color = red >@calculateFunTime</font> 如下:
@calculateFunTime
def A(x, y):
time.sleep(1)
print("A")
return x + y
在調(diào)用該A方法時(shí)候就可計(jì)算出該方法執(zhí)行的時(shí)間:
test1 = testFun(2, 3)
打印如下:
A
fun A 執(zhí)行了 1.0038 s
接下來說明一下<font color = red >@calculateFunTime</font>,借助Pyhton提供的@語法偏塞,將calculateFunTime高階函數(shù)作用在A函數(shù)的定義處即為:
@calculateFunTime
def A(x, y):
time.sleep(1)
print("A")
return x + y
這樣定義之后,在運(yùn)行A方法時(shí)候,執(zhí)行的A方法時(shí),就會(huì)優(yōu)先執(zhí)行calculateFunTime方法中定義的方法.
此時(shí)執(zhí)行A方法:
A = calculateFunTime(A)
由于calculateFunTime是高階函數(shù),允許函數(shù)作為參數(shù)傳入,且函數(shù)calculateFunTime返回也為一個(gè)函數(shù).
A方法執(zhí)行時(shí)候被calculateFunTime方法替換灸叼。
由于calculateFunTime()是一個(gè)decorator,返回一個(gè)函數(shù)屁魏,所以捉腥,原來的A()函數(shù)仍然存在,只是現(xiàn)在同名的A變量指向了新的函數(shù)披诗,于是調(diào)用A()將執(zhí)行新函數(shù),即在calculateFunTime()函數(shù)中返回的wraps()函數(shù)呈队。
wraps()函數(shù)的參數(shù)定義是(*args, **kw)宪摧,因此,wraps()函數(shù)可以接受任意參數(shù)的調(diào)用几于。在wraps()函數(shù)內(nèi),首先打印日志朽砰,再緊接著調(diào)用原始函數(shù)喉刘。
執(zhí)行順序?yàn)?br> calculateFunTime->wraps
返回值依次為fun->wraps
fun方法即為傳入的方法A(此處為A)。
借助高階函數(shù)可接受函數(shù)為參數(shù),可返回函數(shù)的功能睦裳。實(shí)現(xiàn)在函數(shù)運(yùn)行前后動(dòng)態(tài)添加邏輯代碼的功能廉邑。
<font color = red >@functools.wraps(fun)
在calculateFunTime中添加這一行是為了避免有些依賴函數(shù)簽名的代碼執(zhí)行就會(huì)出錯(cuò)。
因?yàn)楹瘮?shù)也是對象.當(dāng)使用@calculateFunTime標(biāo)注了函數(shù)A 之后蛛蒙。函數(shù)A作為參數(shù)傳給calculateFunTime。在運(yùn)行函數(shù)A 時(shí)候相當(dāng)于運(yùn)行了calculateFunTime函數(shù)倍靡。此時(shí)函數(shù)A 依然存在课舍,只不過函數(shù)A 指向了新的高階函數(shù)calculateFunTime。由于函數(shù)calculateFunTime返回的函數(shù)為wraps函數(shù)捡需。因此在調(diào)用函數(shù)A.__name __()時(shí):
沒有添加@functools.wraps(fun)
A.__name__
返回值為:
wraps
在wraps函數(shù)上添加 <font color = red >@functools.wraps(fun) calculateFunTime的返回函數(shù)wraps的name方法返回的值就轉(zhuǎn)為了傳入函數(shù)的name
添加@functools.wraps(fun)
A.__name__
返回值為:
A