7.3
1.裝飾器
裝飾器(decorator)是一種高級(jí)py語(yǔ)法仅叫,裝飾器可以對(duì)一個(gè)函數(shù)膏斤,方法或者類進(jìn)行加工
在py中,我們有多種方法對(duì)函數(shù)和類進(jìn)行加工中剩,裝飾器從操作上入手
為函數(shù)增加額外的指令忌穿,py最初沒(méi)有裝飾器這一語(yǔ)法
裝飾器在py2.5中才出現(xiàn),最初只用于函數(shù)
在py2.6以及之后的py版本中结啼,裝飾器被進(jìn)一步用于類
我們先定義兩個(gè)簡(jiǎn)單的數(shù)學(xué)函數(shù)掠剑,一個(gè)用來(lái)計(jì)算平方和
一個(gè)用來(lái)計(jì)算平方差:
#獲得平方和
def square_sum(a,b):
return a**2 + b**2
#獲得平方差
def square_diff(a,b):
return a**2 - b**2
if __name__ == '__main__':
print(square_sum(3,4)) #打印25
print(square_diff(3,4)) #打印-7
在擁有了基本的數(shù)學(xué)功能之后郊愧,我們可能想為函數(shù)增加其他的功能
比如打印輸入朴译,我們可以改寫(xiě)函數(shù)來(lái)實(shí)現(xiàn)這一點(diǎn):
#裝飾:打印輸入
def square_sum(a,b):
print('input:',a,b)
return a**2 + b**2
def square_diff(a,b):
print('input:',a,b)
return a**2 - b**2
if __name__ == '__main__':
print(square_sum(3,4))
print(square_diff(3,4))
我們修改了函數(shù)定義,為函數(shù)增加了功能属铁,從代碼中可以看到
這兩個(gè)函數(shù)在功能上的拓展有很高的相似性
都是增加了print('input:',a,b)這一打印功能
我們可以改用裝飾器眠寿,定義功能拓展本身
再把裝飾器用于兩個(gè)函數(shù):
def decorator_demo(old_function):
def new_function(a,b):
print('input',a,b) #額外打印操作
return old_function(a,b)
return new_function
@decorator_demo
def square_sum(a,b):
return a**2 + b**2
@decorator_demo
def square_diff(a,b):
return a**2 - b**2
if __name__ == '__main__':
print(square_sum(3,4))
print(square_diff(3,4))
裝飾器可以用def的形式定義,如上面代碼中的decorator_demo()
裝飾器接受一個(gè)可調(diào)用的對(duì)象作為輸入?yún)?shù)红选,并返回一個(gè)新的可調(diào)用對(duì)象
裝飾器新建了一個(gè)函數(shù)對(duì)象澜公,也就是上面的new_function()
在new_function()中,我們?cè)黾恿舜蛴〉墓δ?br>
并通過(guò)調(diào)用old_function(a,b)來(lái)保留原有函數(shù)的功能
定義好裝飾器后,我們就可以通過(guò)@語(yǔ)法使用了
在函數(shù)square_sum()和square_diff()定義之前
調(diào)用@decorator_demo坟乾,實(shí)際上是將square_sum()
或square_diff()傳遞給了decorator_demo()
并將decorator_demo()返回的新的函數(shù)對(duì)象賦給原來(lái)的函數(shù)名
square_sum()和square_diff()
所以當(dāng)我們調(diào)用square_sum(3,4)的時(shí)候迹辐,實(shí)際上發(fā)生的是:
square_sum = decorator_demo(square_sum)
square_sum(3,4)
我們知道,py中的變量名和對(duì)象是分離的
變量名其實(shí)是指向一個(gè)對(duì)象的引用
從本質(zhì)上甚侣,裝飾器起到的作用就是名稱綁定(name binding)
讓同一個(gè)變量名指向一個(gè)新返回的函數(shù)對(duì)象明吩,從而達(dá)到修改函數(shù)對(duì)象的目的
只不過(guò),我們很少?gòu)氐赘暮瘮?shù)對(duì)象殷费,在使用裝飾器時(shí)
我們往往會(huì)在新函數(shù)內(nèi)部調(diào)用舊的函數(shù)印荔,以便保留舊函數(shù)功能
下面看一個(gè)更有實(shí)用功能的裝飾器,我們可以利用time包來(lái)測(cè)量程序運(yùn)行的時(shí)間
把測(cè)量程序運(yùn)行時(shí)間的功能做成一個(gè)裝飾器详羡,將這個(gè)裝飾器運(yùn)用于其他函數(shù)
將顯示函數(shù)的實(shí)際運(yùn)行時(shí)間:
import time
def decorator_timer(old_function):
def new_function(*arg,**dict_arg):
t1 = time.time()
result = old_function(*arg,**dict_arg)
t2 = time.time()
print('time:',t2 - t1)
return result
return new_function
@decorator_timer
def sum(a,b):
c = a + b
return c
if __name__ == '__main__':
print(sum(3,4))
time: 1.1920928955078125e-06
7
在new_function()中仍律,除調(diào)用舊函數(shù)外
還前后額外調(diào)用了一次time.time(),由于time.time()返回掛鐘時(shí)間
它們的差值反映了舊函數(shù)的運(yùn)行時(shí)間实柠,此外水泉,我們通過(guò)打包參數(shù)的方法
可以在新函數(shù)和舊函數(shù)之間傳遞所有的參數(shù)
裝飾器可以實(shí)現(xiàn)代碼的可復(fù)用性,我們可以用同一個(gè)裝飾器修飾多個(gè)函數(shù)
以便實(shí)現(xiàn)相同的附加功能窒盐,比如說(shuō)草则,在建設(shè)網(wǎng)站服務(wù)器時(shí),我們能用不同函數(shù)
表示對(duì)不同HTTP請(qǐng)求的處理蟹漓,當(dāng)我們每次處理HTTP請(qǐng)求前
都想附加一個(gè)客戶驗(yàn)證功能時(shí)炕横,那么就可以定義一個(gè)統(tǒng)一的裝飾器
作用于每一個(gè)處理函數(shù),這樣葡粒,程序能重復(fù)利用份殿,可讀性也大為提高
Python中的函數(shù)的參數(shù)定義和可變參數(shù)
https://www.cnblogs.com/tqsummer/archive/2011/01/25/1944416.html