11

decorator模块的功能与此密切functools.wraps相关。两者之间有什么区别(从 Python 3.3 / 3.4 开始)?

我知道一个区别:3 多年前decorator支持帮助,而wraps没有(另请参阅)。

4

3 回答 3

6

您链接到的文档中列出了主要区别之一:decorator保留包装函数的签名,而wraps没有。

于 2012-12-17T03:22:06.450 回答
6

根据与 BrenBarn 的讨论,现在functools.wraps还保留了包装函数的签名。恕我直言,这使得decorator装饰器几乎过时了。

from inspect import signature
from functools import wraps

def dec(func):
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

def dec2(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

def foo(a: int, b):
    pass

print(signature(dec(foo)))
print(signature(dec2(foo)))

# Prints:
# (*args, **kwargs)
# (a:int, b)

请注意,必须使用signature而不是getargspec. 用 python 3.4 测试。

于 2015-12-14T09:22:37.230 回答
4

有两个区别:

  • decorator即使在 python 3.7中,也能真正保留签名而functools.wraps不会。通过签名,我的意思是当然,而且包装器在不执行的情况下提出正确的,以防用户提供错误的参数。正如这篇文章中所解释的,似乎保留了签名,但并没有真正保留它。help()signature()__dict__TypeError functools.wraps

  • 当参数不是 var-positional 时,decorator您总是会收到参数kwargs- 这使得实现包装器变得更加容易。由于functools.wraps根据名称获取参数值要困难得多,因为它可能在 in *args、 in**kwargs或无处(如果它是可选参数并且不是由用户提供的)

由于我非常喜欢functool.wrapsAPI 但又想解决以上两个问题,所以我创建了makefun. 它提出了一个泛化@wraps,使用与 完全相同的技巧decorator,甚至支持签名修改,例如添加和删除参数。它已经被多个项目使用,请不要犹豫尝试一下!

于 2019-03-26T17:27:53.797 回答