问题描述
在对此的评论中回答另一个问题,有人说他们不确定functools.wraps
在做什么.所以,我问这个问题,以便在StackOverflow上记录下来,以备将来参考:functools.wraps
到底是做什么的?
In a comment on this answer to another question, someone said that they weren't sure what functools.wraps
was doing. So, I'm asking this question so that there will be a record of it on StackOverflow for future reference: what does functools.wraps
do, exactly?
推荐答案
使用装饰器时,您将一个函数替换为另一个.换句话说,如果您有装饰器
When you use a decorator, you're replacing one function with another. In other words, if you have a decorator
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
代替.不幸的是,这意味着如果您再说
and your function f
is replaced with the function with_logging
. Unfortunately, this means that if you then say
print(f.__name__)
它将打印with_logging
,因为这是新功能的名称.实际上,如果您查看f
的文档字符串,它将为空,因为with_logging
没有文档字符串,因此您编写的文档字符串将不再存在.另外,如果您查看该函数的pydoc结果,它将不会被列为带有一个参数x
.而是将其列为*args
和**kwargs
,因为with_logging就是这样.
it will print with_logging
because that's the name of your new function. In fact, if you look at the docstring for f
, it will be blank because with_logging
has no docstring, and so the docstring you wrote won't be there anymore. Also, if you look at the pydoc result for that function, it won't be listed as taking one argument x
; instead it'll be listed as taking *args
and **kwargs
because that's what with_logging takes.
如果使用装饰器总是意味着丢失有关功能的信息,那将是一个严重的问题.这就是为什么我们有functools.wraps
的原因.这将使用装饰器中使用的功能,并添加复制功能名称,文档字符串,参数列表等的功能.由于wraps
本身是装饰器,因此以下代码可以正确执行操作:
If using a decorator always meant losing this information about a function, it would be a serious problem. That's why we have functools.wraps
. This takes a function used in a decorator and adds the functionality of copying over the function name, docstring, arguments list, etc. And since wraps
is itself a decorator, the following code does the correct thing:
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'
这篇关于functools.wraps是做什么的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!