使用 AST 模块改变和删除 assignment/function 个调用
Use AST module to mutate and delete assignment/function calls
例如,如果我想将大于更改为小于或等于,我已成功执行:
def visit_Gt(self, node):
new_node = ast.GtE()
return ast.copy_location(new_node, node)
我如何 visit/detect 赋值操作 (=
) 和函数调用 ()
并简单地删除它们?我正在阅读 AST 文档,但找不到访问赋值或函数调用的方法 类 然后 return 什么也没有。
我正在寻找的赋值操作示例:
print("Start")
x = 5
print("End")
变为:
print("Start")
print("End")
以及我正在寻找的删除函数调用的示例:
print("Start")
my_function_call(Args)
print("End")
变成
print("Start")
print("End")
您可以使用 ast.NodeTransformer()
subclass 来改变现有的 AST 树:
import ast
class RemoveAssignments(ast.NodeTransformer):
def visit_Assign(self, node):
return None
def visit_AugAssign(self, node):
return None
new_tree = RemoveAssignments().visit(old_tree)
上面的class移除None
将节点从输入树中完全移除。 Assign
和 AugAssign
节点包含整个赋值语句,因此生成结果的表达式和目标列表(1 个或多个要将结果分配给的名称)。
这意味着上面会转
print('Start!')
foo = 'bar'
foo += 'eggs'
print('Done!')
进入
print('Start!')
print('Done!')
如果您需要做出更细粒度的决策,请直接查看分配的子节点,或者将子节点传递给 self.visit()
让转换器进一步调用 visit_*
挂钩它们(如果它们存在):
class RemoveFunctionCallAssignments(NodeTransformer):
"""Remove assignments of the form "target = name()", so a single name being called
The target list size plays no role.
"""
def visit_Assign(self, node):
if isinstance(node.value, ast.Call) and isinstance(node.value.func, ast.Name):
return None
return node
这里,我们只return None
如果赋值的值侧(右侧的表达式)是一个 Call
节点应用于直线-转发 Name
节点。返回传入的原始节点对象意味着它不会被替换。
要替换 顶级 函数调用(因此那些没有赋值或进一步表达式的),请查看 Expr
节点;这些是表达式 语句 ,而不仅仅是作为其他构造一部分的表达式。如果你有一个 Expr
节点带有 Call
,你可以删除它:
def visit_Expr(self, node):
# stand-alone call to a single name is to be removed
if isinstance(node.value, ast.Call) and isinstance(node.value.func, ast.Name):
return None
return node
另请参阅带有更多示例的优秀 Green Tree Snakes documentation, which covers working on the AST tree。
例如,如果我想将大于更改为小于或等于,我已成功执行:
def visit_Gt(self, node):
new_node = ast.GtE()
return ast.copy_location(new_node, node)
我如何 visit/detect 赋值操作 (=
) 和函数调用 ()
并简单地删除它们?我正在阅读 AST 文档,但找不到访问赋值或函数调用的方法 类 然后 return 什么也没有。
我正在寻找的赋值操作示例:
print("Start")
x = 5
print("End")
变为:
print("Start")
print("End")
以及我正在寻找的删除函数调用的示例:
print("Start")
my_function_call(Args)
print("End")
变成
print("Start")
print("End")
您可以使用 ast.NodeTransformer()
subclass 来改变现有的 AST 树:
import ast
class RemoveAssignments(ast.NodeTransformer):
def visit_Assign(self, node):
return None
def visit_AugAssign(self, node):
return None
new_tree = RemoveAssignments().visit(old_tree)
上面的class移除None
将节点从输入树中完全移除。 Assign
和 AugAssign
节点包含整个赋值语句,因此生成结果的表达式和目标列表(1 个或多个要将结果分配给的名称)。
这意味着上面会转
print('Start!')
foo = 'bar'
foo += 'eggs'
print('Done!')
进入
print('Start!')
print('Done!')
如果您需要做出更细粒度的决策,请直接查看分配的子节点,或者将子节点传递给 self.visit()
让转换器进一步调用 visit_*
挂钩它们(如果它们存在):
class RemoveFunctionCallAssignments(NodeTransformer):
"""Remove assignments of the form "target = name()", so a single name being called
The target list size plays no role.
"""
def visit_Assign(self, node):
if isinstance(node.value, ast.Call) and isinstance(node.value.func, ast.Name):
return None
return node
这里,我们只return None
如果赋值的值侧(右侧的表达式)是一个 Call
节点应用于直线-转发 Name
节点。返回传入的原始节点对象意味着它不会被替换。
要替换 顶级 函数调用(因此那些没有赋值或进一步表达式的),请查看 Expr
节点;这些是表达式 语句 ,而不仅仅是作为其他构造一部分的表达式。如果你有一个 Expr
节点带有 Call
,你可以删除它:
def visit_Expr(self, node):
# stand-alone call to a single name is to be removed
if isinstance(node.value, ast.Call) and isinstance(node.value.func, ast.Name):
return None
return node
另请参阅带有更多示例的优秀 Green Tree Snakes documentation, which covers working on the AST tree。