装饰模块vs functools.wraps

max*_*max 9 python decorator python-3.x

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

我知道一个区别:3+年前,decorator支持帮助,同时wraps也没有(另见).

Bre*_*arn 6

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


Chi*_*nke 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)
Run Code Online (Sandbox Code Playgroud)

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


sma*_*rie 5

有两个区别:

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

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

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