Python AST NodeTransformer:返回多个节点



在使用ast时,有没有一种简单的方法可以返回多个节点来替换单个节点。节点变压器?例如,假设我想重写表单的所有表达式

f(g())_x1 = g(); g(_x1)

如果visit_Expr可以返回多个节点而不是单个节点,则很容易做到这一点。不过,我似乎无法让它工作,所以我认为这不是这样做的方法。任何建议将不胜感激。

[Update]作为更新,我有一个工作版本,它将新旧节点累积在一个列表中,并将它们分配给封闭范围节点的主体(例如ForWhileModule节点等(。这绝对是一种笨拙的方法,并且怀疑有更好的方法。我会保留这个,以防有人知道。

[final update]查看文档以了解NodeTransformer,如果节点是语句集合的一部分,则实际上完全可以返回节点列表。

对于语句节点,您可以返回新节点的列表。这允许您将单个语句替换为多个语句。引用文档:

对于属于语句集合(适用于所有语句节点(的节点,访问者还可以返回节点列表,而不仅仅是单个节点。

对于表达式,有一个顶级Expr()表达式语句节点:

>>> ast.dump(ast.parse('f(g())'))
"Module(body=[Expr(value=Call(func=Name(id='f', ctx=Load()), args=[Call(func=Name(id='g', ctx=Load()), args=[], keywords=[])], keywords=[]))])"
>>> import ast
>>> ast.dump(ast.parse('f(g())'))
"Module(body=[Expr(value=Call(func=Name(id='f', ctx=Load()), args=[Call(func=Name(id='g', ctx=Load()), args=[], keywords=[])], keywords=[]))])"

因此,您所要做的就是提供一个返回 2 个语句节点列表的visit_Expr处理程序;第一个是调用g()的赋值(Assign()语句节点(,第二个是传入新变量名的调用f(另一个Expr()语句节点(。

我会将状态保留在转换器子类中,该子类在您输入和离开表达式语句上下文时设置标志,并跟踪该上下文下的调用堆栈。然后返回到visit_Expr时,返回新设置:

self._expr_statement = False
def visit_Expr(node):
self._expr_statement = True
self.generic_visit(node)
self._expr_statement = False
if <specific state on self matches expectations>:
tempvar = <generated_new_name>
return [
Assign([Name(tempvar, Store())], <inner_call>),
Expr(Call(
<outer_function_name_expr>,
args=[Name(tempvar, Load())],
keyword=[]))
]
else:
# no replacement takes place
return node

NodeTransformer then uses that list of elements to replace the previousExpr((' 节点。

请注意,您必须调用self.generic_visit(node)仍然以确保仍处理嵌套节点;然后将为这些嵌套节点调用进一步visit_*方法。这样,您就可以在visit_Call方法中检查self._expr_statement标志,然后测试是否存在嵌套调用,然后在self上存储足够的上下文以供返回visit_Expr()方法。

最新更新