使用装饰器时如何保留函数元数据?
装饰器是Python中一个非常强大和有用的工具,因为它允许程序员修改函数或类的行为。装饰器允许我们包装另一个函数以扩展被包装函数的行为,而无需永久修改它。
注意:有关详细信息,请参阅Python中的装饰器
如何保存元数据?
这可以使用 functools 的 wraps() 方法来完成。它通过复制 __name__、__doc__(文档字符串)等属性来更新包装函数,使其看起来像包装函数。
例子:
Python3
import time
from functools import wraps
def timethis(func):
'''Decorator that reports the execution time.'''
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(func.__name__, end-start)
return result
return wrapper
@timethis
def countdown(n:int):
'''Counts down'''
while n > 0:
n -= 1
countdown(100000)
print(countdown.__name__)
print(countdown.__doc__)
print(countdown.__annotations__)
Python3
from inspect import signature
print(signature(countdown))
输出:
countdown 0.00827932357788086
countdown
Counts down
{'n': }
使用 wraps() 的优点:
- 复制装饰器元数据是编写装饰器的重要部分。如果你忘记使用@wraps ,你会发现装饰函数丢失了各种有用的信息。例如,如果省略,最后一个示例的输出将如下所示:
countdown 0.030733823776245117
wrapper
None
{}
- @wraps装饰器的一个重要特性是它使包装函数在__wrapped__属性中可供您使用。例如,如果你想直接访问被包装的函数,你可以这样做:
countdown.__wrapped__(100000)
- __wrapped__属性的存在也使得修饰函数正确地暴露了被包装函数的底层签名。例如:
Python3
from inspect import signature
print(signature(countdown))
- 输出:
(n:int)