如何在Python装饰器中生成值并传递给被装饰函数?
在Python装饰器中注入值到被装饰函数
基础解决方案(硬编码参数名)
直接在装饰器的最内层wrapped函数中完成值的计算与注入,修改后的代码如下:
from flask import request, abort def check_user_agent(allowed_agents): def inner_decorator(f): def wrapped(*args, **kwargs): lowercase_agent = request.user_agent.string.lower() if lowercase_agent not in allowed_agents: abort(401, "This agent is not allowed") # 将小写后的agent值注入到kwargs,对应被装饰函数的lc_agent参数 kwargs['lc_agent'] = lowercase_agent # 若希望保留调用函数时传入的lc_agent值,改用下面这行: # kwargs.setdefault('lc_agent', lowercase_agent) return f(*args, **kwargs) return wrapped return inner_decorator
调用示例(原有代码无需修改,lc_agent会被自动赋值):
@check_user_agent(['curl']) def get(lc_agent = None): return {'message':'Gotten', 'user_agent': lc_agent}
进阶解决方案(动态适配参数名)
如果不想硬编码参数名,可以通过以下两种方式优化:
方式1:装饰器自定义参数名
给装饰器增加参数,指定要注入的参数名:
from flask import request, abort def check_user_agent(allowed_agents, agent_param='lc_agent'): def inner_decorator(f): def wrapped(*args, **kwargs): lowercase_agent = request.user_agent.string.lower() if lowercase_agent not in allowed_agents: abort(401, "This agent is not allowed") kwargs[agent_param] = lowercase_agent return f(*args, **kwargs) return wrapped return inner_decorator
调用时可自定义参数名:
@check_user_agent(['curl'], agent_param='user_agent') def get(user_agent = None): return {'message':'Gotten', 'user_agent': user_agent}
方式2:自动检测函数参数
用inspect模块检查被装饰函数的参数列表,避免注入不存在的参数导致报错:
import inspect from flask import request, abort def check_user_agent(allowed_agents): def inner_decorator(f): # 获取被装饰函数的参数列表 sig = inspect.signature(f) func_params = list(sig.parameters.keys()) def wrapped(*args, **kwargs): lowercase_agent = request.user_agent.string.lower() if lowercase_agent not in allowed_agents: abort(401, "This agent is not allowed") # 仅当函数存在目标参数时才注入 if 'lc_agent' in func_params: kwargs['lc_agent'] = lowercase_agent return f(*args, **kwargs) return wrapped return inner_decorator
核心逻辑说明
- 注入操作必须放在
wrapped函数中,因为这里是拦截被装饰函数调用的入口,所有参数都会经过此处。 - 修改
kwargs是最稳妥的方式,既不会破坏原有的位置参数args,也能精准传递指定参数。 - 使用
kwargs.setdefault()替代直接赋值时,仅当参数未被调用者传入时,才会注入装饰器生成的值。
内容的提问来源于stack exchange,提问作者Wige
相关产品推荐
相关产品推荐

