装饰器带参数时是三层函数嵌套:第一层接收装饰器参数并返回第二层,第二层接收被装饰函数并返回第三层,第三层接收调用参数并执行逻辑;缺一不可,否则报错或失效。

装饰器带参数时,本质是“三层函数嵌套”:最外层接收装饰器参数,中间层接收被装饰函数,最内层接收函数调用时的参数。关键在于理清每一层的职责和返回时机。
第一层:接收装饰器本身的参数
这一层函数(常叫decorator_factory)在@语法执行时被立即调用,传入的是你写在@后面括号里的值,比如@retry(max_times=3)中的max_times=3。它不接触被装饰函数,只负责“配置”后续行为。
- 必须返回第二层函数(即真正的装饰器)
- 参数通常用于初始化状态或生成配置,如重试次数、超时阈值、日志前缀等
- 支持关键字/位置参数,建议统一用
**kwargs增强灵活性
第二层:接收并包装被装饰函数
这一层(常叫decorator)在Python加载函数定义时被调用,接收的是原函数对象(如def fetch_data(): ...)。它的任务是返回一个新函数,替代原函数被调用。
- 可在此层做函数元信息保存(如
functools.wraps(func)) - 可预处理函数属性,比如绑定配置、注册到某列表、打日志
- 必须返回第三层函数(即包装后的可调用对象)
第三层:实际执行逻辑与参数转发
这一层(常叫wrapper)在运行时被触发,接收原函数调用时的所有参数(*args, **kwargs)。它是真正插入逻辑(如计时、校验、重试)的位置,也必须把参数原样或修改后传给原函数。
立即学习“Python免费学习笔记(深入)”;
- 务必用
*args, **kwargs接收并透传,确保兼容任意签名 - 可在调用前后加逻辑:记录开始时间→执行原函数→记录结束时间→计算耗时
- 若需修改输入或输出,要明确是否影响原语义(例如缓存装饰器会跳过原函数调用)
通用封装建议:用类实现更清晰
当装饰器参数多、逻辑复杂或需维护状态(如累计调用次数、共享缓存字典),用类替代闭包更易读可控。类的__init__对应第一层,__call__对应第二层,而wrapper逻辑可单独抽成方法。
-
__init__(self, max_times=1, delay=0):存装饰器参数 -
__call__(self, func):返回包装函数,同时保存self.func = func - 内部
_execute_with_retry(self, *args, **kwargs):专注核心逻辑,解耦清晰
不复杂但容易忽略:三层返回缺一不可,漏掉任一层都会导致TypeError: 'function' object is not callable或装饰失效。写完可快速验证:@my_dec(arg=1)是否能正常修饰函数,且修饰后函数仍可带参调用。










