装饰器在函数定义时就完成包装,即模块加载时执行@decorator等价于func=decorator(func);带参装饰器需三层嵌套,多装饰器按从下到上顺序嵌套,须用functools.wraps保留元信息。

装饰器在函数定义时就完成包装
Python 装饰器不是在函数调用时才起作用,而是在 @ 语法解析阶段、函数对象被创建后立即执行。这意味着 @decorator 实际等价于 func = decorator(func),且该赋值发生在模块加载时。
常见错误现象:在装饰器内部打印日志却没看到输出——很可能是因为模块没被导入,或者装饰器写成了带括号形式但未正确返回可调用对象。
- 如果写成
@my_decorator(),必须确保my_decorator()返回一个接收函数的闭包 - 装饰器链如
@a @b def f(): ...等价于f = a(b(f)),即从下往上套用(b先包,再被a包) - 类装饰器需实现
__call__方法;函数装饰器返回的必须是可调用对象
带参数的装饰器要多嵌套一层
当你看到 @retry(max_attempts=3) 这种带参数的写法,它背后其实是三层函数结构:最外层接收装饰器参数,中间层接收被装饰函数,最内层才是实际执行逻辑。
容易踩的坑是漏掉某一层返回,导致 TypeError: 'NoneType' object is not callable。
立即学习“Python免费学习笔记(深入)”;
- 典型骨架:
def retry(max_attempts):→def decorator(func):→def wrapper(*args, **kwargs):→return wrapper→return decorator - 若中间层忘记
return decorator,则@retry(...)展开后得到的是None,后续绑定失败 - 使用
functools.wraps(func)在 wrapper 内部保留原函数元信息,否则help(f)或序列化会出问题
多个装饰器叠加时注意执行顺序和作用域
装饰器叠加不是“并行生效”,而是形成嵌套调用链。外层装饰器的 wrapper 调用内层装饰器的 wrapper,最终才到原始函数。
可编程序控制器,英文称Programmable Controller,简称PC。但由于PC容易和个人计算机(Personal Computer)混淆,故人们仍习惯地用PLC作为可编程序控制器的缩写。它是一个以微处理器为核心的数字运算操作的电子系统装置,专为在工业现场应用而设计,它采用可编程序的存储器,用以在其内部存储执行逻辑运算、顺序控制、定时/计数和算术运算等操作指令,并通过数字式或模拟式的输入、输出接口,控制各种类型的机械或生产过程。本平台提供PLC编程入门基础知识下载,需要的朋友们下载看看吧!
这意味着:前置逻辑按装饰器声明顺序从上到下执行,后置逻辑则反过来(类似栈的压入与弹出)。
def log_calls(func):
def wrapper(*args):
print(f"→ calling {func.__name__}")
result = func(*args)
print(f"← done {func.__name__}")
return result
return wrapper
def add_prefix(func):
def wrapper(*args):
print("[prefix] before")
result = func(*args)
print("[prefix] after")
return result
return wrapper
@log_calls
@add_prefix
def say(x):
return f"hello {x}"
调用 say("world") 输出顺序为:→ calling say → [prefix] before → [prefix] after → ← done say。可见 log_calls 的前后逻辑包裹了整个 add_prefix 流程。
装饰器中访问闭包变量或 self 容易引发状态混淆
装饰器本身是模块级代码,其内部定义的变量(如计数器、缓存字典)在所有被装饰函数间共享。如果是类方法装饰器,还可能误把实例状态当成装饰器状态。
典型错误:用一个全局字典记录调用次数,结果多个函数共用同一计数器;或在类装饰器里把 self 当作被装饰方法的实例传入。
- 避免全局状态污染:每个被装饰函数应有独立上下文,可用
functools.partial或闭包绑定专属数据 - 装饰实例方法时,
wrapper接收的第一个参数是self,但该self是调用时的对象,不是装饰器类的self - 若需绑定实例生命周期,考虑用描述符(descriptor)替代函数装饰器
真正麻烦的从来不是语法怎么写,而是哪一层 closure 捕获了哪个变量,以及那个变量是不是你认为的那个“它”。









