如何在 Python 中找到 ast 节点及其子节点

How to find ast nodes and its sub nodes in Python

我正在尝试遍历 Python 中的 ast 节点,以获取所有分配节点的值节点的名称 ID。 Ast.walk() 方法随机给我节点。

假设:仅用于分配节点

for node in ast.walk(tree):


    if isinstance(node,(ast.Assign)):
        if isinstance(node.value,(ast.Name)):
            print('Assign Value:-','lineno: ',node.value.lineno,' id :',node.value.id)
        if isinstance(node.value,(ast.Tuple)):
            for i in range(len(node.value.elts)):
                if isinstance(node.value.elts[i],(ast.Name)):
                    print('Assign Value:-','lineno: ',node.value.elts[i].lineno,' id :',node.value.elts[i].id)

在这里,有时ast会在值节点内给出BinOps、Call等。我必须在值节点中获取 Name.id。

Ex: a,b = (c+d), e --> 预期值应该是 c,d,e..但我只得到 e 。另外,如何将 (c,d) 标记为目标 'a' .

可以从分配节点获取目标。

您可以 walk 原始 ast,并且对于每个 ast.Assign,递归提取目标名称和关联值 ids:

import ast
def names(a):
   return [i.id for i in ast.walk(a) if isinstance(i, ast.Name)]

def bindings(target, value):
   if isinstance(target, ast.Name):
      yield [target.id, names(value)]
   elif isinstance(target, (ast.List, ast.Tuple)):
      if not isinstance(value, (ast.List, ast.Tuple)):
         yield [tuple(names(target)), names(value)]
      else:
         for a, b in zip(target.elts, value.elts):
            yield from bindings(a, b)

def assign_bindings(s):
   return [dict(bindings(i.targets[0], i.value)) for i in ast.walk(ast.parse(s)) 
            if isinstance(i, ast.Assign)]

上面的代码允许您传递 assign_bindings 一个源字符串,该字符串具有带解包的赋值语句、单个名称绑定、元组、表达式等:

print(assign_bindings('a, b = (c+d), e'))
print(assign_bindings('a, [b, c, [d, [e]]] = [n1, [n2, n3, [n4, [n5]]]]'))
print(assign_bindings('vals = func(a + b)'))

输出:

[{'a': ['c', 'd'], 'b': ['e']}]
[{'a': ['n1'], 'b': ['n2'], 'c': ['n3'], 'd': ['n4'], 'e': ['n5']}]
[{'vals': ['func', 'a', 'b']}]