老生常談Python進(jìn)階之裝飾器
函數(shù)也是對(duì)象
要理解Python裝飾器,首先要明白在Python中,函數(shù)也是一種對(duì)象,因此可以把定義函數(shù)時(shí)的函數(shù)名看作是函數(shù)對(duì)象的一個(gè)引用。既然是引用,因此可以將函數(shù)賦值給一個(gè)變量,也可以把函數(shù)作為一個(gè)參數(shù)傳遞或返回。同時(shí),函數(shù)體中也可以再定義函數(shù)。
裝飾器本質(zhì)
可以通過(guò)編寫一個(gè)純函數(shù)的例子來(lái)還原裝飾器所要做的事。
def decorator(func): def wrap(): print("Doing someting before executing func()") func() print("Doing someting after executing func()") return wrap def fun_test(): print("func") fun_test = decorator(fun_test) fun_test() # Output: # Doing someting before executing func() # func # Doing someting after executing func()
fun_test所指向的函數(shù)的引用傳遞給decorator()函數(shù)
decorator()函數(shù)中定義了wrap()子函數(shù),這個(gè)子函數(shù)會(huì)調(diào)用通過(guò)func引用傳遞進(jìn)來(lái)的fun_test()函數(shù),并在調(diào)用函數(shù)的前后做了一些其他的事情
decorator()函數(shù)返回內(nèi)部定義的wrap()函數(shù)引用
fun_test接收decorator()返回的函數(shù)引用,從而指向了一個(gè)新的函數(shù)對(duì)象
通過(guò)fun_test()調(diào)用新的函數(shù)執(zhí)行wrap()函數(shù)的功能,從而完成了對(duì)fun_test()函數(shù)的前后裝飾
Python中使用裝飾器
在Python中可以通過(guò)@符號(hào)來(lái)方便的使用裝飾器功能。
def decorator(func): def wrap(): print("Doing someting before executing func()") func() print("Doing someting after executing func()") return wrap @decorator def fun_test(): print("func") fun_test() # Output: # Doing someting before executing func() # func # Doing someting after executing func()
裝飾的功能已經(jīng)實(shí)現(xiàn)了,但是此時(shí)執(zhí)行:
print(fun_test.__name__) # Output: # wrap
fun_test.__name__已經(jīng)變成了wrap,這是應(yīng)為wrap()函數(shù)已經(jīng)重寫了我們函數(shù)的名字和注釋文檔。此時(shí)可以通過(guò)functools.wraps來(lái)解決這個(gè)問(wèn)題。wraps接受一個(gè)函數(shù)來(lái)進(jìn)行裝飾,并加入了復(fù)制函數(shù)名稱、注釋文檔、參數(shù)列表等等功能。這可以讓我們?cè)谘b飾器里面訪問(wèn)在裝飾之前的函數(shù)的屬性。
更規(guī)范的寫法:
from functools import wraps def decorator(func): @wraps(func) def wrap(): print("Doing someting before executing func()") func() print("Doing someting after executing func()") return wrap @decorator def fun_test(): print("func") fun_test() print(fun_test.__name__) # Output: # Doing someting before executing func() # func # Doing someting after executing func() # fun_test
帶參數(shù)的裝飾器
通過(guò)返回一個(gè)包裹函數(shù)的函數(shù),可以模仿wraps裝飾器,構(gòu)造出一個(gè)帶參數(shù)的裝飾器。
from functools import wraps def loginfo(info='info1'): def loginfo_decorator(func): @wraps(func) def wrap_func(*args, **kwargs): print(func.__name__ + ' was called') print('info: %s' % info) return func(*args, **kwargs) return wrap_func return loginfo_decorator @loginfo() def func1(): pass func1() # Output: # func1 was called # info: info1 @loginfo(info='info2') def func2(): pass func2() # Output: # func2 was called # info: info2
裝飾器類
通過(guò)編寫類的方法也可以實(shí)現(xiàn)裝飾器,并讓裝飾器具備繼承等面向?qū)ο笾懈鼘?shí)用的特性
首先編寫一個(gè)裝飾器基類:
from functools import wraps class loginfo: def __init__(self, info='info1'): self.info = info def __call__(self, func): @wrap def wrap_func(*args, **kwargs): print(func.__name__ + ' was called') print('info: %s' % self.info) self.after() # 調(diào)用after方法,可以在子類中實(shí)現(xiàn) return func(*args, **kwargs) return wrap_func def after(self): pass @loginfo(info='info2') def func1(): pass # Output: # func1 was called # info: info1
再通過(guò)繼承l(wèi)oginfo類,擴(kuò)展裝飾器的功能:
class loginfo_after(loginfo): def __init__(self, info2='info2', *args, **kwargs): self.info2 = info2 super(loginfo_after, self).__init__(*args, **kwargs) def after(self): print('after: %s' % self.info2) @loginfo_after() def func2(): pass func2() # Output: # func2 was called # info: info1 # after: info2
以上這篇老生常談Python進(jìn)階之裝飾器就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
python實(shí)現(xiàn)銀行實(shí)戰(zhàn)系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)銀行實(shí)戰(zhàn)系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-02-02Pytorch自定義Dataset和DataLoader去除不存在和空數(shù)據(jù)的操作
這篇文章主要介紹了Pytorch自定義Dataset和DataLoader去除不存在和空數(shù)據(jù)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-03-03Python pytest.main()運(yùn)行測(cè)試用例
這篇文章主要介紹了Python pytest.main()運(yùn)行測(cè)試用例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2022-12-12PyTorch里面的torch.nn.Parameter()詳解
今天小編就為大家分享一篇PyTorch里面的torch.nn.Parameter()詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-01-01pandas 如何保存數(shù)據(jù)到excel,csv
這篇文章主要介紹了pandas 如何保存數(shù)據(jù)到excel,csv的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07Python入門Anaconda和Pycharm的安裝和配置詳解
這篇文章主要介紹了Python入門Anaconda和Pycharm的安裝和配置詳解,文章通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07python密碼學(xué)列置換密碼學(xué)習(xí)
這篇文章主要為大家介紹了python密碼學(xué)列置換密碼學(xué)習(xí)的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05