內(nèi)容純屬個(gè)人理解,不對(duì)之處,歡迎指點(diǎn)。
裝飾問題:__name__和__doc__
接著上回分解,在我們給函數(shù)添加了計(jì)算運(yùn)行時(shí)間的功能后(準(zhǔn)確來說應(yīng)該是執(zhí)行某函數(shù)時(shí)我們同時(shí)對(duì)函數(shù)做了一些操作,畢竟一個(gè)函數(shù)的存在就是為了完成某一個(gè)具體的功能,而不是多個(gè)),其實(shí)裝飾器也對(duì)函數(shù)做了一些其他的修改。
示例:
def deco(func):
'''i am deco'''
def wrap(*args, **kwargs):
'''i am wrap'''
return func(*args, **kwargs)
return wrap
@deco
def foo():
'''i am foo'''
print("---foo---")
當(dāng)我們執(zhí)行foo():
>> foo()
---foo---
此時(shí)似乎還沒有問題,但是當(dāng)我們查看函數(shù)文檔和函數(shù)名字時(shí):
>> foo.__doc__
'i am wrap'
>> foo.__name__
'wrap'
此時(shí)問題就來了,函數(shù)的信息被修改了,然而這并不是我們想要的結(jié)果,究其原因,還是裝飾器裝飾過程中的問題。
我們來看一下裝飾器的裝飾過程:
1. wrap = deco(foo) # 將foo函數(shù)傳入deco函數(shù),并返回內(nèi)部的wrap函數(shù)
2. foo = wrap # 將wrap函數(shù)賦給foo
3. foo() # 執(zhí)行foo函數(shù)
由上可以看到,此時(shí)的foo已經(jīng)不是原來的foo了,確切的說,它已經(jīng)變成了wrap,是wrap賦值給了foo,所以才有了執(zhí)行foo時(shí)可以執(zhí)行添加的功能,也就是執(zhí)行了wrap。所以當(dāng)我們查看foo函數(shù)的docstring和name時(shí),顯示的是wrap函數(shù)的docstring和name。
問題總有解決的辦法。
from functools import wraps
def deco(func):
'''i am deco'''
@wraps(func)
def wrap(*args, **kwargs):
'''i am wrap'''
return func(*args, **kwargs)
return wrap
@deco
def foo():
'''i am foo'''
print("---foo---")
此時(shí)再運(yùn)行:
>> foo()
---foo---
>> foo.__name__
foo
>> foo.__doc__
i am foo
functools中的wraps可以保留原函數(shù)的__name__和__doc__,不使其發(fā)生改變,這樣才是更好的裝飾。