wraps 将许多属性从另一个函数复制到此函数上 - 默认情况下,__module__、__name__、__qualname__、__annotations__ 和 __doc__。
最明显有用的复制是__doc__。考虑这个更简单的例子:1
class Base:
def spam(self, breakfast):
"""spam(self, breakfast) -> breakfast with added spam
<29 lines of detailed information here>
"""
class Child:
@functools.wraps(Base.spam)
def spam(self, breakfast):
newbreakfast = breakfast.copy()
newbreakfast.meats['spam'] + 30
return newbreakfast
现在如果有人想使用help(mychild.spam),他们将获得 29 行有用的信息。 (或者,如果他们在 PyCharm 中自动完成 mychild.spam,它会弹出带有文档等的叠加层。)所有这些都无需我手动复制和粘贴。而且,更好的是,如果Base 来自某个我没有编写的框架,并且我的用户从该框架的 1.2.3 升级到 1.2.4,并且有更好的文档字符串,他们会看到更好的文档字符串。
在最常见的情况下,Child 将是 Base 的子类,spam 将是覆盖。2 但实际上这不是必需的 - wraps 不需要'不在乎您是通过继承进行子类型化,还是通过实现隐式协议来进行子类型化;它对这两种情况同样有用。只要Child 旨在实现Base 中的spam 协议,Child.spam 就可以具有相同的文档字符串(可能还有其他元数据属性)。
其他属性可能不如文档字符串有用。例如,如果您使用类型注释,它们在阅读代码方面的好处可能至少与它们能够运行 Mypy 进行静态类型检查的好处一样高,因此通常不会从另一个方法动态复制它们所有这些有用的。 __module__ 和 __qualname__ 主要用于反射/检查,在这种情况下更容易产生误导而不是帮助(尽管您可能会想出一个框架示例,希望人们阅读Base 中的代码,而不是 Child 中的代码,这对于默认的明显示例不正确)。但是,除非它们是有害的,否则使用 @functools.wraps(Base.spam, assigned=('__doc__',)) 而不仅仅是默认值的可读性成本可能不值得。
1。如果您使用的是 Python 2,请将这些类更改为从 object 继承;否则它们将是老式的类,只会以不相关的方式使事情复杂化。如果是 Python 3,没有老式的类,所以这个问题甚至不会出现。
2。或者可能是 ABC 的“虚拟子类”,通过 register 调用或子类挂钩声明。