Python 中如何创建函数装饰器(并叠加多个装饰器)?

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__ 拿到未装饰的原函数。

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台