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

