📜  使用装饰器时如何保留函数元数据?

📅  最后修改于: 2022-05-13 01:54:36.978000             🧑  作者: Mango

使用装饰器时如何保留函数元数据?

装饰器是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)