装饰模块vs functools.wraps

时间:2012-12-17 02:43:23

标签: python python-3.x decorator

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

我发现一个区别:3+ years agodecorator支持帮助,而wraps没有(另请参阅this)。

3 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:3)

根据与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测试。

答案 2 :(得分:0)

有两个区别:

  • decorator真正保留签名,而functools.wraps则不保留签名,即使在python 3.7中也是如此。签名,当然是指help()signature()以及所有__dict__,但是包装程序会提出正确的TypeError 而根本不执行如果用户提供了错误的参数。如this post中所述,functools.wraps 出现是为了保留签名,但并没有真正保留它。

  • 使用decorator
  • 总是在kwargs中收到参数时,它们不是可变位置的-这使实现包装器变得容易得多。使用functools.wraps时,根据其名称获取参数值要困难得多,因为它可能位于*args**kwargs或其他任何地方(如果它是可选参数且未由用户提供)

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

相关问题