使用 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将节点从输入树中完全移除。 AssignAugAssign 节点包含整个赋值语句,因此生成结果的表达式和目标列表(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