在 ipython 中输入以下代码后,输入后续的
func_with_wrap?
将显示 <no docstring>
,而 func_no_wrap?
将按预期显示文档字符串。我怎样才能让 func_with_wrap?
正确显示文档字符串?
def wrap(f):
"""
wrap docstring
"""
def wrapped():
return
return wrapped
@wrap
def func_with_wrap():
"""
func_with_wrap docstring
"""
return
def func_no_wrap():
"""
func_no_wrap docstring
"""
return
以下是输出:
In [12]: func_with_wrap?
Signature: func_with_wrap()
Docstring: <no docstring>
File: c:\confidential>
Type: function
In [13]: func_no_wrap?
Signature: func_no_wrap()
Docstring: func_no_wrap docstring
File: c:\confidential>
Type: function
因为函数
def wrapped():
(在 wrap
内声明)没有文档字符串,所以 func_with_wrap
不存在文档字符串。装饰器通过将函数替换为传递给装饰函数的装饰器的返回值来处理函数。它基本上等同于以下命名的 lambda 行为:
func_with_wrap = lambda: <code that was in 'def func_with_wrap' block>
func_with_wrap = wrap(func_with_wrap)
虽然您可以将文档字符串添加到示例中的内部
def wrapped
调用中,但这会有点不寻常。由于大多数装饰器(正如您的符号名称所暗示的)是增强装饰函数而不是完全用其他东西替换它的包装器,因此从函数传播属性(如文档字符串、函数名称和类型注释)被认为是最佳实践。在您的示例中包裹 - func_with_wrap
- 装饰器的返回值 - 在您的示例中wrapped
。
functools.wraps
来做到这一点,就像这样:
from functools imports wraps
def wrap(f):
"""
wrap docstring
"""
@wraps(f)
def wrapped():
...
return wrapped
您也可以手动执行此操作,通过手动将装饰函数中的
__doc__
分配给装饰器的返回值,如下所示:
def wrap(f):
"""
wrap docstring
"""
def wrapped():
...
wrapped.__doc__ = f.__doc__
return wrapped