装饰器在函数定义完成时立即执行,而非调用时;即@decorator在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),它拿到的是定义时的值,不是运行时的最新值 - 类方法上的装饰器,同样在类体执行完毕、方法对象创建后立刻生效,与实例创建无关










