Python 装饰器的执行时机到底是什么?

10次阅读

装饰器在函数定义完成时立即执行,而非调用时;即@decorator在python生成函数对象后立刻用其包装或替换原函数,发生在模块导入或脚本执行到该函数定义处的那一刻。

Python 装饰器的执行时机到底是什么?

装饰器在函数被定义完成时立即执行,不是在函数被调用时。也就是说,@decorator 这一行代码的作用,是在 Python 解析完函数体、生成函数对象后,立刻用装饰器对这个函数对象进行包装或替换。

装饰器本质是函数对象的“编译期”处理

Python 解释器读到 def my_func(): ... 时,会: – 先创建函数对象(my_func 是一个可调用对象) – 然后检查它上面有没有装饰器 – 如果有(比如 @log_calls),就立刻把该函数对象作为参数传给 log_calls,并用返回值覆盖原名字 my_func

这个过程发生在模块导入(import)或脚本执行到该函数定义处的那一刻,和后续是否调用 my_func() 完全无关。

装饰器函数本身在定义时运行,被装饰函数的逻辑在调用时运行

以常见写法为例:

def log_calls(func):     print(f"[装饰阶段] 正在包装函数 {func.__name__}")     def wrapper(*args, **kwargs):         print(f"[运行阶段] 调用 {func.__name__}")         return func(*args, **kwargs)     return wrapper 

@log_calls def greet(name): return f"Hello, {name}!"

当你运行这段代码(比如直接执行或 import),你会立刻看到:

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

[装饰阶段] 正在包装函数 greet

[运行阶段] 那行输出,只有在你手动调用 greet("Alice") 时才会出现。

带参数的装饰器多一层“工厂”调用

@retry(max_times=3) 这种带参数的装饰器,实际执行顺序是三步:

  • 先调用 retry(max_times=3) → 返回一个真正的装饰器函数(比如叫 decorator
  • 再用这个 decorator 去装饰目标函数(即 decorator(greet)
  • 最后把返回结果赋给 greet

所以第一层函数(retry)在定义被装饰函数时就执行了;第二层(真正的装饰器)也在同一时刻执行;只有最内层的 wrapper 逻辑,留到函数被调用时才跑。

装饰器执行时机影响实际行为

理解这点能避免常见陷阱:

  • 装饰器里写的 print、日志、注册逻辑、配置读取等,都只发生一次(函数定义时),不是每次调用都触发
  • 如果在装饰器中捕获了外部变量(如闭包中的 config),它拿到的是定义时的值,不是运行时的最新值
  • 类方法上的装饰器,同样在类体执行完毕、方法对象创建后立刻生效,与实例创建无关

text=ZqhQzanResources