内容纯属个人理解,不对之处,欢迎指点。
装饰问题:__name__和__doc__
接着上回分解,在我们给函数添加了计算运行时间的功能后(准确来说应该是执行某函数时我们同时对函数做了一些操作,毕竟一个函数的存在就是为了完成某一个具体的功能,而不是多个),其实装饰器也对函数做了一些其他的修改。
示例:
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---")
当我们执行foo():
>> foo()
---foo---
此时似乎还没有问题,但是当我们查看函数文档和函数名字时:
>> foo.__doc__
'i am wrap'
>> foo.__name__
'wrap'
此时问题就来了,函数的信息被修改了,然而这并不是我们想要的结果,究其原因,还是装饰器装饰过程中的问题。
我们来看一下装饰器的装饰过程:
1. wrap = deco(foo) # 将foo函数传入deco函数,并返回内部的wrap函数
2. foo = wrap # 将wrap函数赋给foo
3. foo() # 执行foo函数
由上可以看到,此时的foo已经不是原来的foo了,确切的说,它已经变成了wrap,是wrap赋值给了foo,所以才有了执行foo时可以执行添加的功能,也就是执行了wrap。所以当我们查看foo函数的docstring和name时,显示的是wrap函数的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---")
此时再运行:
>> foo()
---foo---
>> foo.__name__
foo
>> foo.__doc__
i am foo
functools中的wraps可以保留原函数的__name__和__doc__,不使其发生改变,这样才是更好的装饰。