decorator
模块的功能与此密切functools.wraps
相关。两者之间有什么区别(从 Python 3.3 / 3.4 开始)?
3 回答
您链接到的文档中列出了主要区别之一:decorator
保留包装函数的签名,而wraps
没有。
根据与 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 测试。
有两个区别:
decorator
即使在 python 3.7中,也能真正保留签名而functools.wraps
不会。通过签名,我的意思是当然,而且包装器在不执行的情况下提出正确的,以防用户提供错误的参数。正如这篇文章中所解释的,似乎保留了签名,但并没有真正保留它。help()
signature()
__dict__
TypeError
functools.wraps
当参数不是 var-positional 时,
decorator
您总是会收到参数kwargs
- 这使得实现包装器变得更加容易。由于functools.wraps
根据名称获取参数值要困难得多,因为它可能在 in*args
、 in**kwargs
或无处(如果它是可选参数并且不是由用户提供的)
由于我非常喜欢functool.wraps
API 但又想解决以上两个问题,所以我创建了makefun
. 它提出了一个泛化@wraps
,使用与 完全相同的技巧decorator
,甚至支持签名修改,例如添加和删除参数。它已经被多个项目使用,请不要犹豫尝试一下!