使用inspect无法直接获取装饰器传入的参数,但可通过解析函数源代码或手动存储装饰器参数的方式间接获取,其中解析源代码的方法仅适用于特定场景,手动存储参数的方法更具通用性。
解析函数源代码获取装饰器参数通过inspect.getsource获取函数源代码,再使用ast模块解析源代码中的抽象语法树(AST),从中提取装饰器参数。这种方法仅适用于代码结构清晰、装饰器参数为字面量(如字符串、数字、元组等)的情况,对于动态生成的参数或复杂场景可能无法准确解析。
实现步骤
使用inspect.getsource获取被装饰函数的源代码。
使用ast.parse将源代码解析为AST。
遍历AST,找到函数定义节点(ast.FunctionDef)。
遍历函数定义节点的装饰器列表(decorator_list),找到目标装饰器调用节点(ast.Call)。
从装饰器调用节点的关键字参数(keywords)中提取参数名和值。
示例代码
import inspectimport astdef get_decorator_args(func, decorator_name): source = inspect.getsource(func) tree = ast.parse(source) for node in ast.walk(tree): if isinstance(node, ast.FunctionDef): for decorator in node.decorator_list: if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Name) and decorator.func.id == decorator_name: args = {} for keyword in decorator.keywords: args[keyword.arg] = ast.literal_eval(keyword.value) return args return {}def task(_id, params): def decorator(func): def wrapper(*args, kwargs): return func(*args, kwargs) return wrapper return decorator@task(_id="aaa", params=(1, 2, 3))def foo(q=1): passprint(get_decorator_args(foo, "task")) # 输出: {'_id': 'aaa', 'params': (1, 2, 3)}手动存储装饰器参数(推荐方法)在装饰器内部将传入的参数存储在函数的属性或闭包变量中,这样可以直接通过函数对象获取这些参数。这种方法具有通用性,适用于各种场景。
from functools import wrapsdef task(_id, params): def decorator(func): @wraps(func) def wrapper(*args, kwargs): return func(*args, kwargs) wrapper.__decorator_args__ = {"_id": _id, "params": params} return wrapper return decorator@task(_id="aaa", params=(1, 2, 3))def foo(q=1): passprint(foo.__decorator_args__) # 输出: {'_id': 'aaa', 'params': (1, 2, 3)}对比两种方法总结如果需要获取装饰器传入的参数,推荐使用手动存储参数的方法,这种方法具有通用性和可靠性。解析源代码的方法仅适用于特定场景,如代码分析工具或静态检查工具的开发。