在对此answer to another question的评论中,有人说他们不确定functools.wraps在做什么。所以,我问这个问题,以便在StackOverflow上有它的记录,以备将来引用: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__)

它将打印with_logging,因为这是新函数的名称。实际上,如果您查看f的文档字符串,它将为空,因为with_logging没有文档字符串,因此您编写的文档字符串将不再存在。另外,如果您查看该函数的pydoc结果,它将不会被列为带有一个参数x;相反,它将被列为*args**kwargs,因为with_logging就是这样做的。

如果使用装饰器总是意味着丢失有关功能的信息,那将是一个严重的问题。这就是为什么我们有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 - functools.wraps是做什么的?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/308999/

10-11 12:52