当前位置: 首页 > 知识库问答 >
问题:

python如何通过inspect获取装饰器传入的参数?

田英卓
2024-07-16

代码如下,想解析装饰器的参数

import inspect
from functools import wraps

def task(_id, params):
    
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            return func(*args, **kwargs)

        return wrapper

    return decorator

@task(_id="aaa", params=(1,2,3))
def foo(q=1):
    ...

if __name__ == '__main__':
    print(inspect.getclosurevars(foo.__wrapped__).nonlocals)  # 不生效,期望获取(_id="aaa", params=(1,2,3))信息

共有2个答案

戚飞雨
2024-07-16

inspect应该做不到了。目前一种方案就是AI给你说的那种,你需要在decorator中去自己存储你的变量。还有一种方案是去针对性的解析你这个代码,但是不是通用性的。

import ast

def get_decorator_args(func):
    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 decorator.func.id == "task":
                    args = {
                        arg.arg: ast.literal_eval(arg.value)
                        for arg in decorator.keywords
                    }
                    return args
    return {}

只适合你这个问题。

print(get_decorator_args(foo)) 

# {'_id': 'aaa', 'params': (1, 2, 3)}
尚安平
2024-07-16

在Python中,装饰器是通过在函数上应用一个返回另一个函数的函数来工作的。由于装饰器通常不直接在被装饰的函数对象上存储其参数,因此你不能直接通过inspect模块来检索这些参数。但是,你可以通过一些技巧来间接地获取这些信息。

一种方法是使用类来模拟装饰器的行为,并在类的实例中存储这些参数。这样,你可以通过类的实例来访问这些参数。下面是一个使用类来模拟装饰器的例子:

from functools import wraps

class TaskDecorator:
    def __init__(self, _id, params):
        self._id = _id
        self.params = params

    def __call__(self, func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # 在这里,你可以使用 self._id 和 self.params
            # 如果你想在函数执行时传递这些参数,你可能需要修改 wrapper 的逻辑
            return func(*args, **kwargs)

        # 我们可以将装饰器的参数附加到 wrapper 函数上作为一个属性
        # 注意:这不是标准做法,可能会与未来版本的Python或库冲突
        wrapper.task_info = {'_id': self._id, 'params': self.params}
        return wrapper

def task(_id, params):
    return TaskDecorator(_id, params)

@task(_id="aaa", params=(1,2,3))
def foo(q=1):
    pass

if __name__ == '__main__':
    # 直接从 wrapper 函数上获取我们附加的 task_info 属性
    print(foo.task_info)  # 输出: {'_id': 'aaa', 'params': (1, 2, 3)}

在这个例子中,我们创建了一个TaskDecorator类来模拟装饰器的行为。我们在类的实例中存储了装饰器的参数,并在__call__方法中返回了一个包装函数wrapper。我们还给wrapper函数附加了一个task_info属性,用于存储装饰器的参数。然后,你可以直接从被装饰的函数上访问这个属性来获取装饰器的参数。

请注意,将额外的属性附加到被装饰的函数上可能不是最佳实践,因为这可能会与未来版本的Python或库发生冲突。但是,这种方法在某些情况下可能是有用的,特别是当你需要在运行时访问这些参数时。

另一种方法是使用模块级别的变量或字典来存储这些参数,但这需要更复杂的逻辑来确保正确地关联装饰器的参数和被装饰的函数。

 类似资料:
  • 问题内容: 我正在使用python flask框架。我编写了一个需要一个参数的装饰器,该参数是动态的。 我的装饰器如下所示,将获得一个密钥,并使用该密钥从redis获取数据。 而且我有一个使用这种装饰器的类,像这样的代码 如您所见,我的装饰器需要一个名为的参数,然后像这样传递密钥 将获得城市的ID,如果一切正常,密钥将如下所示 但我得到了错误: 我很困惑,在烧瓶中,如何将动态参数传递给装饰器? 谢

  • 问题内容: 我在装饰器传递变量时遇到问题。我可以通过以下装饰器语句来做到这一点: 但不幸的是,该声明不起作用。也许也许有更好的方法来解决此问题。 问题答案: 带参数的装饰器的语法有些不同-带参数的装饰器应返回一个函数,该函数将接受一个函数并返回另一个函数。因此,它实际上应该返回一个普通的装饰器。有点混乱吧?我的意思是: 在这里,你可以阅读有关该主题的更多信息-也可以使用可调用对象来实现此目的,这也

  • 本文向大家介绍如何获取路由传过来的参数?相关面试题,主要包含被问及如何获取路由传过来的参数?时的应答技巧和注意事项,需要的朋友参考一下 如果使用方式传入的参数使用 接收 如果使用方式传入的参数使用接收 参考:路由组件传参

  • 装饰器(decorator)是一种高级Python语法。装饰器可以对一个函数、方法或者类进行加工。在Python中,我们有多种方法对函数和类进行加工,比如在Python闭包中,我们见到函数对象作为某一个函数的返回结果。相对于其它方式,装饰器语法简单,代码可读性高。因此,装饰器在Python项目中有广泛的应用。 装饰器最早在Python 2.5中出现,它最初被用于加工函数和方法这样的可调用对象(ca

  • 本文向大家介绍python通过装饰器检查函数参数数据类型的方法,包括了python通过装饰器检查函数参数数据类型的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了python通过装饰器检查函数参数数据类型的方法。分享给大家供大家参考。具体分析如下: 这段代码定义了一个python装饰器,通过此装饰器可以用来检查指定函数的参数是否是指定的类型,在定义函数时加入此装饰器可以非常清晰的检测函

  • 问题内容: 我想定义一些通用装饰器,以在调用某些函数之前检查参数。 就像是: 旁注: 类型检查只是在这里显示一个示例 我正在使用Python 2.7,但是Python 3.0也会很有趣 问题答案: 从装饰器的功能和方法: Python 2 Python 3 在Python 3中已更改为,并且已更改为。 用法: 可以是或