三层嵌套装饰器中,外层负责参数接收与校验并返回中间层,中间层绑定目标函数并返回内层包装器,内层执行运行时逻辑并调用原函数;类装饰器适用于需维持状态或提供额外接口的场景。

装饰器多层嵌套本身不是“容器注入”,而是函数式闭包结构的自然延伸;所谓“层级设置技巧”,本质是控制参数绑定时机、作用域可见性与执行逻辑分离。关键不在“注入”,而在三层嵌套中各层职责的清晰划分。
外层:专注参数接收与校验
这一层接收装饰器调用时传入的配置参数(如 @cache(ttl=300, key_prefix="user:") 中的 ttl 和 key_prefix),它不接触被装饰函数,也不处理运行时参数。所有参数合法性检查必须放在这里——比如判断 ttl 是否为正数、key_prefix 是否为字符串。一旦校验失败,应立即抛出异常,避免延迟到函数调用时才暴露问题。
- 参数值会通过闭包持久化,供内层使用
- 返回的是中间层函数(即真正的装饰器),不能直接返回包装器
- 避免在此层做耗时操作,它在模块导入或定义时就执行一次
中间层:绑定函数,返回包装器
这一层接收被装饰的目标函数(func),负责构造并返回第三层的 wrapper。它是闭包链的承上启下节点:既捕获外层传入的配置,又准备接收后续调用时的 *args 和 **kwargs。注意,这里不做实际逻辑执行,只做“准备”。
- 必须用 @functools.wraps(func) 修饰内层 wrapper,否则 __name__、__doc__ 等元信息丢失
- 不要在此层访问运行时参数(如 args),它们属于第三层的管辖范围
- 若需复用配置或维护轻量状态(如统计装饰器被应用了多少次),可在此层初始化局部变量
内层:执行逻辑,调用原函数
这是真正响应每次函数调用的地方。它接收运行时参数,结合外层绑定的配置和中间层传入的 func,完成增强行为(如打日志、查缓存、重试、权限校验等),最后显式调用 func(*args, **kwargs) 并返回结果。
- 所有与调用上下文相关的判断放在这里(例如根据 args[0].role 决定是否放行)
- 异常处理也应在此层,便于区分“装饰逻辑异常”和“原函数异常”
- 避免在此层修改外层参数(如重新赋值 ttl),它们应视为只读配置
类装饰器作为替代方案的适用场景
当需要跨多次调用维持状态(如累计调用次数、动态更新缓存策略)、或参数组合复杂导致三层函数嵌套难以维护时,类装饰器更直观。它把外层参数存在实例属性里,中间层对应 __init__,内层对应 __call__,逻辑分层同样清晰,且天然支持属性修改和方法复用。
- 适合带状态、需初始化、或需提供额外接口(如 .clear_cache())的场景
- 类实例本身可被 inspect、调试、序列化,比闭包更易观测
- 注意实现 __repr__ 和继承 functools.update_wrapper 来保持元信息











