Python装饰器参数解析:如何用inspect或其他方法获取装饰器传入的参数?

Python装饰器参数解析:如何用inspect或其他方法获取装饰器传入的参数?
最新回答
海枯鱼亡

2020-12-17 12:22:16

使用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)}手动存储装饰器参数(推荐方法)

在装饰器内部将传入的参数存储在函数的属性或闭包变量中,这样可以直接通过函数对象获取这些参数。这种方法具有通用性,适用于各种场景。

  • 实现步骤

    在装饰器内部,将传入的参数存储在函数的属性中(如__decorator_args__)。

    通过函数对象的属性直接获取装饰器参数。

  • 示例代码

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)}对比两种方法
  • 解析源代码方法

    优点:无需修改装饰器代码,适用于分析已有代码。

    缺点:仅适用于特定场景,对代码结构要求较高,无法处理动态参数。

  • 手动存储参数方法

    优点:通用性强,适用于各种场景,代码简洁明了。

    缺点:需要修改装饰器代码,添加参数存储逻辑。

总结

如果需要获取装饰器传入的参数,推荐使用手动存储参数的方法,这种方法具有通用性和可靠性。解析源代码的方法仅适用于特定场景,如代码分析工具或静态检查工具的开发。