functools.wraps是做什么的?
在对另一个问题的答案的评论中,有人说他们不确定在做什么。所以,我问这个问题是为了在StackOverflow上有一个记录,以供将来参考:到底做了什么?functools.wraps
functools.wraps
在对另一个问题的答案的评论中,有人说他们不确定在做什么。所以,我问这个问题是为了在StackOverflow上有一个记录,以供将来参考:到底做了什么?functools.wraps
functools.wraps
使用装饰器时,会将一个函数替换为另一个函数。换句话说,如果你有一个装饰器
def logged(func):
def with_logging(*args, **kwargs):
print(func.__name__ + " was called")
return func(*args, **kwargs)
return with_logging
然后当你说
@logged
def f(x):
"""does some math"""
return x + x * x
这与说的完全一样
def f(x):
"""does some math"""
return x + x * x
f = logged(f)
并且您的函数将替换为函数 。不幸的是,这意味着如果你然后说f
with_logging
print(f.__name__)
它将打印,因为这是您的新函数的名称。事实上,如果你看一下 docstring for ,它将是空白的,因为没有 docstring,所以你写的 docstr 将不再存在。另外,如果您查看该函数的pydoc结果,它不会被列为采用一个参数;相反,它将被列为采取,因为这是with_logging采取的。with_logging
f
with_logging
x
*args
**kwargs
如果使用装饰器总是意味着丢失有关函数的此信息,那将是一个严重的问题。这就是为什么我们有.这采用装饰器中使用的函数,并添加复制函数名称,文档字符串,参数列表等的功能。由于它本身就是一个装饰器,因此以下代码执行正确的操作:functools.wraps
wraps
from functools import wraps
def logged(func):
@wraps(func)
def with_logging(*args, **kwargs):
print(func.__name__ + " was called")
return func(*args, **kwargs)
return with_logging
@logged
def f(x):
"""does some math"""
return x + x * x
print(f.__name__) # prints 'f'
print(f.__doc__) # prints 'does some math'
从python 3.5 +开始:
@functools.wraps(f)
def g():
pass
是 的别名。它只做三件事:g = functools.update_wrapper(g, f)
__module__
__name__
__qualname__
__doc__
__annotations__
f
g
WRAPPER_ASSIGNMENTS
__dict__
g
f.__dict__
WRAPPER_UPDATES
__wrapped__=f
g
结果是,看起来与 具有相同的名称、文档字符串、模块名称和签名。唯一的问题是,关于签名,这实际上不是真的:它只是默认遵循包装链。您可以使用文档中的说明进行检查。这会产生令人讨厌的后果:g
f
inspect.signature
inspect.signature(g, follow_wrapped=False)
Signature.bind()
现在和装饰器之间有点混淆,因为开发装饰器的一个非常常见的用例是包装函数。但两者都是完全独立的概念。如果您有兴趣了解其中的区别,我为两者实现了帮助器库:decopatch可以轻松编写装饰器,并使makefun为.请注意,它依赖于与著名库相同的经过验证的技巧。functools.wraps
@wraps
makefun
decorator