装饰器本质是接受函数并返回新函数的高阶函数,其能力来源于 Python 的闭包与一等函数特性。
一、基础装饰器与 functools.wraps
python
import functools
def timer(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
import time
start = time.perf_counter()
result = func(*args, **kwargs)
print(f"{func.__name__} took {time.perf_counter() - start:.4f}s")
return result
return wrapperfunctools.wraps 将原函数的 __name__、__doc__ 等元数据复制到包装函数,避免调试与文档生成出错。
二、类装饰器与描述符
当装饰器作用于方法时,需注意描述符协议:函数本身是描述符,__get__ 返回绑定方法。若包装函数未正确处理 self,会导致方法调用异常。使用 functools.wraps 并结合 __set_name__ 可编写健壮的类装饰器。