Python装饰器执行顺序_调用链解析【教程】

7次阅读

装饰器执行分定义和调用两阶段:定义时自下而上包装,调用时自上而下执行;带参装饰器先执行工厂函数再包装;日志可清晰追踪调用链。

Python 装饰器执行顺序_调用链解析【教程】

装饰器的执行顺序分两个阶段:定义时的包装顺序,和调用时的执行顺序。理解这两者的 区别,是搞懂多层装饰器的关键。

装饰器定义时:从下往上包装

当你写多个装饰器叠加时,Python 会按从下到上的顺序应用它们(即离函数最近的先执行)。这决定了最终函数对象的结构。

例如:

@decorator_a @decorator_b @decorator_c def my_func():     pass

等价于:

立即学习Python 免费学习笔记(深入)”;

my_func = decorator_a(decorator_b(decorator_c(my_func)))

也就是说,decorator_c 最先被调用,包装原函数;然后 decorator_b 包装 decorator_c 的返回值;最后 decorator_a 包装整个结果。

函数调用时:从上往下执行

虽然包装是自下而上,但真正调用 my_func() 时,执行流程是反过来的:最外层装饰器先拿到控制权,再一层层往里传。

  • 调用 my_func() → 进入 decorator_a 的 wrapper
  • wrapper 中调用 func() → 实际是 decorator_b 的 wrapper
  • 再调用其内部 func() → 实际是 decorator_c 的 wrapper
  • 最后才执行原始函数体

带参数的装饰器:多一层函数嵌套

@retry(max_attempts=3) 这类装饰器,本质是“装饰器工厂”,它返回真正的装饰器。

执行顺序仍是两阶段:

  • 定义时:retry(max_attempts=3) 先运行,返回一个装饰器函数;该函数再按前述规则去包装目标函数
  • 调用时:仍遵循外层 wrapper → 内层 wrapper → 原函数的链式调用路径

可以这样理解:每多一层 @,就多一次函数调用和一次包装;而带参装饰器在 @ 那一刻就完成了一次“预计算”。

调试技巧:加打印快速理清链条

在每个装饰器的 wrapper 开头和结尾加日志,能直观看到执行流:

def log_call(name):     def decorator(func):         def wrapper(*args, **kwargs):             print(f"[进入] {name}")             result = func(*args, **kwargs)             print(f"[退出] {name}")             return result         return wrapper     return decorator  @log_call("A") @log_call("B") @log_call("C") def hello():     print("hello world")

调用 hello() 输出为:

[进入] A [进入] B [进入] C hello world [退出] C [退出] B [退出] A

清楚展示了“进时由外向内,出时由内向外”的调用 行为。

text=ZqhQzanResources