gpt4 book ai didi

python - 如何使用 Python 自省(introspection)查找对方法的调用?

转载 作者:太空宇宙 更新时间:2023-11-04 04:16:12 27 4
gpt4 key购买 nike

我刚刚在一个项目中发现一些测试方法没有所需的“test_”前缀来确保它们实际运行。应该可以通过一些 linting 来避免这种情况:

  1. 在代码库中查找所有 TestCase 断言调用。
  2. 在调用层次结构中查找名称以“test_”开头的方法。
  3. 如果没有这样的方法,打印一条错误信息。

我想知道如何解决前两个问题,这基本上可以归结为一个问题:如何在我的代码库中找到对特定方法的所有调用?

Grepping 或其他文本搜索行不通,因为我需要反省结果并找到父方法等,直到我找到测试方法或没有更多调用者为止。我需要获取方法的引用,以避免匹配的方法恰好与我要查找的方法同名。

最佳答案

这里有两种可能的方法。

  1. 静态方法:

    您可以使用 ast 模块解析代码库以识别所有函数调用并一致地存储调用的来源和目标。您将必须识别所有类和函数定义以跟踪每个调用的当前上下文。这里的限制是,如果调用实例方法,则没有简单的方法来识别该方法实际属于哪个类。如果您使用引用模块的变量也是如此

    这里有一个 Visitor 子类,可以读取 Python 源文件并构建一个字典 {caller: callee}:

    class CallMapper(ast.NodeVisitor):
    def __init__(self):
    self.ctx = []
    self.funcs = []
    self.calls = collections.defaultdict(set)
    def process(self, filename):
    self.ctx = [('M', os.path.basename(filename)[:-3])]
    tree = ast.parse(open(filename).read(), filename)
    self.visit(tree)
    self.ctx.pop()
    def visit_ClassDef(self, node):
    print('ClassDef', node.name, node.lineno, self.ctx)
    self.ctx.append(('C', node.name))
    self.generic_visit(node)
    self.ctx.pop()
    def visit_FunctionDef(self, node):
    print('FunctionDef', node.name, node.lineno, self.ctx)
    self.ctx.append(('F', node.name))
    self.funcs.append('.'.join([elt[1] for elt in self.ctx]))
    self.generic_visit(node)
    self.ctx.pop()
    def visit_Call(self, node):
    print('Call', vars(node.func), node.lineno, self.ctx)
    try:
    id = node.func.id
    except AttributeError:
    id = '*.' + node.func.attr
    self.calls['.'.join([elt[1] for elt in self.ctx])].add(id)
    self.generic_visit(node)
  2. 动态方法:

    如果你真的想确定调用的是什么方法,当多个方法可以共享相同的名称时,你将不得不使用动态方法。您可以装饰类中的单个函数或所有方法,以计算它们被调用的次数,以及它们被调用的位置(可选)。然后您将开始测试并检查实际发生的情况。

    这是一个函数,它将装饰一个类中的所有方法,以便所有调用的次数都将存储在字典中:

    def tracemethods(cls, track):
    def tracker(func, track):
    def inner(*args, **kwargs):
    if func.__qualname__ in track:
    track[func.__qualname__] += 1
    else:
    track[func.__qualname__] = 1
    return func(*args, *kwargs)
    inner.__doc__ = func.__doc__
    inner.__signature__ = inspect.signature(func)
    return inner
    for name, func in inspect.getmembers(cls, inspect.isfunction):
    setattr(cls, name, tracker(func, track))

    您可以调整该代码以浏览解释器堆栈以识别每次调用的调用者,但这并不容易,因为您获得了调用者函数的非限定名称并且必须使用文件名和行号来唯一识别来电者。

关于python - 如何使用 Python 自省(introspection)查找对方法的调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55368638/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com