Python 中如何创建函数装饰器(并叠加多个装饰器)?
Python 装饰器是包装函数的高阶函数:定义一个接收函数、返回包装函数的函数,用 @语法应用。多个装饰器从下往上依次包装。本文给出完整教程。
装饰器本质:一个接收函数、返回新函数的函数。用 @装饰器名 放在目标函数上面即可应用。多个装饰器从下往上依次包装。
创建装饰器
import functools
def my_decorator(func):
@functools.wraps(func) # 保留原函数的元信息
def wrapper(*args, **kwargs):
print("函数调用前")
result = func(*args, **kwargs)
print("函数调用后")
return result
return wrapper
@my_decorator
def greet(name):
print(f"你好, {name}")
greet("张三")
# 输出: 函数调用前 → 你好, 张三 → 函数调用后
@functools.wraps(func) 很重要:保留原函数的 __name__、__doc__,否则调试和文档工具会拿到 wrapper 的信息。
带参数的装饰器
再加一层函数接收参数:
import time
import functools
def timing(unit="s"):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
print(f"{func.__name__} 耗时 {time.perf_counter()-start:.4f}{unit}")
return result
return wrapper
return decorator
@timing(unit="ms")
def slow_func():
time.sleep(0.5)
多个装饰器叠加
@decorator_a
@decorator_b
def func():
pass
# 等价于 func = decorator_a(decorator_b(func))
# 执行顺序:a 的前置 → b 的前置 → func → b 的后置 → a 的后置
观测云对照
手写计时装饰器适合开发调试;生产环境观测云 APM 探针自动记录每个方法的耗时并生成调用链火焰图,不需要给每个函数加装饰器。
常见问题(FAQ)
Q:装饰器能用于类方法吗?
A:能,wrapper 的第一个参数会收到 self,用 *args, **kwargs 透传即可。
Q:装饰类本身怎么做?
A:装饰器同样可以接收类并返回修改后的类:@dataclass 就是典型例子。
Q:如何写"可移除"的装饰器?
A:functools.wraps 会把原函数存到 __wrapped__ 属性,可以 func.__wrapped__ 拿到未装饰的原函数。