为什么Python装饰器会丢失函数属性__doc__?
def decor(fun):
def living(*args, **kw):
return fun(*args, **kw)
return living
@decor
def test():
'''function doc'''
pass
print test.__doc__
为什么结果是 None
呢?我在使用装饰器的时候发生了什么?谢谢大家的回答!
2 个回答
0
这是因为你的装饰器实际上是在替换你的函数。你需要使用 functools.wraps()
来保存被装饰函数的一些内部信息,比如 __name__
和 __doc__
。
你可以通过给你的装饰器函数 living()
添加一个文档字符串来简单测试这一点:
>>> def decor(fun):
... def living(*args, **kw):
... """This is the decorator for living()"""
... return fun(*args, **kw)
... return living
...
>>> @decor
... def test():
... """function doc"""
... pass
...
>>> test.__doc__
'This is the decorator for living()'
这是来自 functools.wraps()
文档的例子,它保存了被包装函数的名称和文档字符串。
>>> from functools import wraps
>>> def my_decorator(f):
... @wraps(f)
... def wrapper(*args, **kwds):
... print 'Calling decorated function'
... return f(*args, **kwds)
... return wrapper
...
>>> @my_decorator
... def example():
... """Docstring"""
... print 'Called example function'
...
>>> example()
Calling decorated function
Called example function
>>> example.__name__
'example'
>>> example.__doc__
'Docstring'
1
当你把一个函数放在装饰器里时:
@decor
def test:
你得到的是装饰器创建的函数(在这个例子中是living
),这个函数没有原来的文档字符串等信息。它并不是“丢失”了这些数据,而是living
根本就没有这些信息!
你可以通过使用functools.wraps
来解决这个问题:
from functools import wraps
def decor(fun):
@wraps(fun)
def living(*args, **kw):
...
return func
这里有个简单的演示来证明这个观点:
>>> def wrapper(f):
def func(*args):
"""The wrapper func's docstring."""
return f(*args)
return func
>>> @wrapper
def test(x):
"""The test func's docstring."""
return x ** 2
>>> test.__doc__
"The wrapper func's docstring."
对比一下
>>> from functools import wraps
>>> def wrapper(f):
@wraps(f)
def func(*args):
"""The wrapper func's docstring."""
return f(*args)
return func
>>> @wrapper
def test(x):
"""The test func's docstring."""
return x ** 2
>>> test.__doc__
"The test func's docstring."