Python編程中裝飾器的使用示例解析
裝飾函數(shù)和方法
我們先定義兩個(gè)簡(jiǎn)單的數(shù)學(xué)函數(shù),一個(gè)用來(lái)計(jì)算平方和,一個(gè)用來(lái)計(jì)算平方差:
# get square sum def square_sum(a, b): return a**2 + b**2 # get square diff def square_diff(a, b): return a**2 - b**2 print(square_sum(3, 4)) print(square_diff(3, 4))
在擁有了基本的數(shù)學(xué)功能之后,我們可能想為函數(shù)增加其它的功能,比如打印輸入。我們可以改寫(xiě)函數(shù)來(lái)實(shí)現(xiàn)這一點(diǎn):
# modify: print input # get square sum def square_sum(a, b): print("intput:", a, b) return a**2 + b**2 # get square diff def square_diff(a, b): print("input", a, b) return a**2 - b**2 print(square_sum(3, 4)) print(square_diff(3, 4))
我們修改了函數(shù)的定義,為函數(shù)增加了功能。
現(xiàn)在,我們使用裝飾器來(lái)實(shí)現(xiàn)上述修改:
def decorator(F): def new_F(a, b): print("input", a, b) return F(a, b) return new_F # get square sum @decorator def square_sum(a, b): return a**2 + b**2 # get square diff @decorator def square_diff(a, b): return a**2 - b**2 print(square_sum(3, 4)) print(square_diff(3, 4))
裝飾器可以用def的形式定義,如上面代碼中的decorator。裝飾器接收一個(gè)可調(diào)用對(duì)象作為輸入?yún)?shù),并返回一個(gè)新的可調(diào)用對(duì)象。裝飾器新建了一個(gè)可調(diào)用對(duì)象,也就是上面的new_F。new_F中,我們?cè)黾恿舜蛴〉墓δ?,并通過(guò)調(diào)用F(a, b)來(lái)實(shí)現(xiàn)原有函數(shù)的功能。
定義好裝飾器后,我們就可以通過(guò)@語(yǔ)法使用了。在函數(shù)square_sum和square_diff定義之前調(diào)用@decorator,我們實(shí)際上將square_sum或square_diff傳遞給decorator,并將decorator返回的新的可調(diào)用對(duì)象賦給原來(lái)的函數(shù)名(square_sum或square_diff)。 所以,當(dāng)我們調(diào)用square_sum(3, 4)的時(shí)候,就相當(dāng)于:
square_sum = decorator(square_sum) square_sum(3, 4)
我們知道,Python中的變量名和對(duì)象是分離的。變量名可以指向任意一個(gè)對(duì)象。從本質(zhì)上,裝飾器起到的就是這樣一個(gè)重新指向變量名的作用(name binding),讓同一個(gè)變量名指向一個(gè)新返回的可調(diào)用對(duì)象,從而達(dá)到修改可調(diào)用對(duì)象的目的。
與加工函數(shù)類(lèi)似,我們可以使用裝飾器加工類(lèi)的方法。
如果我們有其他的類(lèi)似函數(shù),我們可以繼續(xù)調(diào)用decorator來(lái)修飾函數(shù),而不用重復(fù)修改函數(shù)或者增加新的封裝。這樣,我們就提高了程序的可重復(fù)利用性,并增加了程序的可讀性。
含參的裝飾器
在上面的裝飾器調(diào)用中,比如@decorator,該裝飾器默認(rèn)它后面的函數(shù)是唯一的參數(shù)。裝飾器的語(yǔ)法允許我們調(diào)用decorator時(shí),提供其它參數(shù),比如@decorator(a)。這樣,就為裝飾器的編寫(xiě)和使用提供了更大的靈活性。
# a new wrapper layer def pre_str(pre=''): # old decorator def decorator(F): def new_F(a, b): print(pre + "input", a, b) return F(a, b) return new_F return decorator # get square sum @pre_str('^_^') def square_sum(a, b): return a**2 + b**2 # get square diff @pre_str('T_T') def square_diff(a, b): return a**2 - b**2 print(square_sum(3, 4)) print(square_diff(3, 4))
上面的pre_str是允許參數(shù)的裝飾器。它實(shí)際上是對(duì)原有裝飾器的一個(gè)函數(shù)封裝,并返回一個(gè)裝飾器。我們可以將它理解為一個(gè)含有環(huán)境參量的閉包。當(dāng)我們使用@pre_str('^_^')調(diào)用的時(shí)候,Python能夠發(fā)現(xiàn)這一層的封裝,并把參數(shù)傳遞到裝飾器的環(huán)境中。該調(diào)用相當(dāng)于:
square_sum = pre_str('^_^') (square_sum)
裝飾類(lèi)
在上面的例子中,裝飾器接收一個(gè)函數(shù),并返回一個(gè)函數(shù),從而起到加工函數(shù)的效果。在Python 2.6以后,裝飾器被拓展到類(lèi)。一個(gè)裝飾器可以接收一個(gè)類(lèi),并返回一個(gè)類(lèi),從而起到加工類(lèi)的效果。
def decorator(aClass): class newClass: def __init__(self, age): self.total_display = 0 self.wrapped = aClass(age) def display(self): self.total_display += 1 print("total display", self.total_display) self.wrapped.display() return newClass @decorator class Bird: def __init__(self, age): self.age = age def display(self): print("My age is",self.age) eagleLord = Bird(5) for i in range(3): eagleLord.display()
在decorator中,我們返回了一個(gè)新類(lèi)newClass。在新類(lèi)中,我們記錄了原來(lái)類(lèi)生成的對(duì)象(self.wrapped),并附加了新的屬性total_display,用于記錄調(diào)用display的次數(shù)。我們也同時(shí)更改了display方法。
通過(guò)修改,我們的Bird類(lèi)可以顯示調(diào)用display的次數(shù)了。
相關(guān)文章
Python 使用dict實(shí)現(xiàn)switch的操作
這篇文章主要介紹了Python 使用dict實(shí)現(xiàn)switch的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-04-04Python基于最小二乘法實(shí)現(xiàn)曲線(xiàn)擬合示例
這篇文章主要介紹了Python基于最小二乘法實(shí)現(xiàn)曲線(xiàn)擬合,涉及Python基于numpy及scipy庫(kù)進(jìn)行曲線(xiàn)擬合操作相關(guān)運(yùn)算技巧,需要的朋友可以參考下2018-06-06Python編程在flask中模擬進(jìn)行Restful的CRUD操作
今天小編就為大家分享一篇關(guān)于Python編程在flask中模擬進(jìn)行Restful的CRUD操作,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12解決Python獲取字典dict中不存在的值時(shí)出錯(cuò)問(wèn)題
今天小編就為大家分享一篇解決Python獲取字典dict中不存在的值時(shí)出錯(cuò)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-10-10tensorflow: 查看 tensor詳細(xì)數(shù)值方法
今天小編就為大家分享一篇tensorflow: 查看 tensor詳細(xì)數(shù)值方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-06-06Python入門(mén)教程(三十九)Python的NumPy安裝與入門(mén)
這篇文章主要介紹了Python入門(mén)教程(三十九)Python的NumPy安裝與入門(mén),NumPy 是一個(gè)Python包,它是一個(gè)由多維數(shù)組對(duì)象和用于處理數(shù)組的例程集合組成的庫(kù),,需要的朋友可以參考下2023-05-05