今天在看这个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函数构成闭包的原因是:
- 它是在另一个函数(decorator)内部定义的
- 它使用了外部函数的参数(func)
- 它被作为返回值返回,并在外部函数作用域结束后仍然可以访问func
这种结构在装饰器模式中很常见,因为它允许我们:
- 保持对原始函数的引用
- 在不改变原始函数的情况下添加新功能
- 维护函数调用的上下文