学习datawhale教程时候看代码-理解装饰器

今天在看这个agent的构建时候, 遇到了API-KEY的问题 ,然后在这个代码中遇到了装饰器,终于学明白装饰器的用法了。 

    def decorator(func: F) -> F:
        @wraps(func)
        def wrapper(*args: Any, **kwargs: Any) -> Any:
            signature = inspect.signature(func)
            bound_arguments = signature.bind(*args, **kwargs)
            bound_arguments.apply_defaults()
            arguments = bound_arguments.arguments

            missing_keys = []
            for param_name, env_var_name in param_env_list:
                if not isinstance(env_var_name, str):
                    raise TypeError(
                        f"Environment variable name must be a string, got"
                        f" {type(env_var_name)}"
                    )

                value = None
                if (
                    param_name
                ):  # If param_name is provided, check function argument first
                    if not isinstance(param_name, str):
                        raise TypeError(
                            f"Parameter name must be a string, "
                            f"got {type(param_name)}"
                        )
                    value = arguments.get(param_name)
                    # If we found a valid value in arguments, continue to next
                    # item
                    if value:
                        continue

                # Check environment variable if no valid value found yet
                value = os.environ.get(env_var_name)
                if not value or value.strip() == "":
                    missing_keys.append(env_var_name)

            if missing_keys:
                raise ValueError(
                    "Missing or empty required API keys in "
                    f"environment variables: {', '.join(missing_keys)}"
                )
            return func(*args, **kwargs)

        return cast(F, wrapper)

    return decorator

这个装饰器的主要作用是检查环境变量中的 API 密钥,它包装了原始函数,在调用前进行验证。如果缺少必要的 API 密钥,就抛出异常,否则正常调用原函数

wrapper函数确实使用了外层函数decorator的参数func:

def decorator(func: F) -> F:            # 外层函数的参数func
    def wrapper(*args: Any, **kwargs: Any) -> Any:   
        # ...中间代码...
        return func(*args, **kwargs)    # 使用了外层函数的func参数
    return wrapper

对比一个更简单的闭包例子:

def outer(x):           # 外层函数
    def inner(y):       # 内层函数
        return x + y    # 内层函数使用了外层函数的变量x
    return inner

# 使用闭包
add_5 = outer(5)   # add_5现在是一个携带了x=5的函数
result = add_5(3)  # 结果是8

在Java中的类似实现:

public interface Calculator {
    int calculate(int y);
}

public class ClosureExample {
    public Calculator outer(int x) {
        // 通过匿名内部类或lambda实现闭包
        return y -> x + y;  // 内部函数捕获了外部变量x
    }
}

回到原始代码,wrapper函数构成闭包的原因是:

  1. 它是在另一个函数(decorator)内部定义的
  2. 它使用了外部函数的参数(func)
  3. 它被作为返回值返回,并在外部函数作用域结束后仍然可以访问func

这种结构在装饰器模式中很常见,因为它允许我们:

  1. 保持对原始函数的引用
  2. 在不改变原始函数的情况下添加新功能
  3. 维护函数调用的上下文
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值