xqqlyx

拆解Python装饰器工厂:从语法糖到本质

拆解Python装饰器工厂:从语法糖到本质

装饰器工厂的核心可归结为函数嵌套调用 + 闭包传状态

一、示例

from functools import wraps

# 1. 定义装饰器工厂
def contract(pre=None, post=None):
    def decorator(func):
        @wraps(func)  # 保留原函数元信息
        def wrapper(*args, **kwargs):
            # 前置检查
            for check in pre or []:
                if not check(*args, **kwargs):
                    raise ValueError("前置条件失败")
            # 执行原函数
            result = func(*args, **kwargs)
            # 后置检查
            for check in post or []:
                if not check(result, *args, **kwargs):
                    raise AssertionError("后置条件失败")
            return result
        return wrapper
    return decorator

# 2. 定义检查函数+被装饰函数
def is_positive(x): return x > 0
def returns_even(res, x): return res % 2 == 0

@contract(pre=[is_positive], post=[returns_even])
def double(x): return x * 2

# 3. 调用测试
print(double(4))   # ✅ 8
# print(double(-1)) # ❌ 抛ValueError

二、@语法糖的本质

@contract(pre=[...], post=[...]) 不是魔法,只是一行代码的简写:

# 装饰器语法 = 手动调用等价写法
double = contract(pre=[is_positive], post=[returns_even])(double)

三、三层调用链

装饰器工厂的三层结构,对应“配置-绑定-执行”三个阶段:

  1. 配置层contract(pre=[...], post=[...])
    调用工厂函数,传入条件参数,返回decorator函数(闭包捕获条件)。
  2. 绑定层decorator(double)
    传入原函数,返回wrapper函数(闭包捕获原函数+条件)。
  3. 执行层wrapper(4)
    调用包装函数,执行“检查-原函数-检查”逻辑,返回结果。

完整调用链等价写法:

(contract(pre=[is_positive], post=[returns_even])(double))(4)

总结

  1. 装饰器工厂本质是三层函数嵌套,@语法是函数调用的语法糖;
  2. 核心逻辑:@factory(参数)factory(参数)(原函数) → 执行包装函数;
  3. 关键:闭包保存状态、*args/**kwargs透传参数、@wraps保留原函数信息。

被装饰函数 = 装饰器工厂(配置参数)(原函数),就能拆解所有带参数的装饰器。

posted on 2026-01-20 16:26  烫烫烫烫热  阅读(0)  评论(0)    收藏  举报