使用AST模块来更改和删除分配/函数调用 [英] Use AST module to mutate and delete assignment/function calls

查看:201
本文介绍了使用AST模块来更改和删除分配/函数调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

例如,如果我想更改大于或小于等于我已成功执行,则

  def visit_Gt( self,node):
new_node = ast.GtE()
return ast.copy_location(new_node,node)

我将如何访问/检测赋值操作( = )和函数调用()并删除它们?我正在阅读AST文档,但找不到找到访问赋值或函数调用类然后不返回任何内容的方法。



我的示例m寻求分配操作:

  print( Start)
x = 5
print( End )

成为:

  print(开始)

print(结束)

以及我要删除的函数调用示例:

  print( Start) 
my_function_call(Args)
print( End)

成为

  print(开始)

打印(结束)


解决方案

您可以使用 ast.NodeTransformer()子类来更改现有的AST树:

  import ast 

类RemoveAssignments(ast.NodeTransformer):
def visit_Assign(自身,节点):
返回无

def visit_AugAssign(自身,节点):
返回无

new_tree = RemoveAssignments()。visit(old_tree)

以上类删除从输入树中完全删除该节点。 Assign AugAssign 节点包含整个赋值语句,因此产生结果的表达式以及目标列表(1或更多名称来将结果分配给该名称。)



这意味着上面的内容将会变成

  print('开始!')
foo ='bar'
foo + ='鸡蛋'
print('完成!')

进入

  print('开始!')


打印('完成!')

如果您需要做出更细粒度的决策,请直接查看分配的子节点,或者将子节点传递给 self.visit()如果存在的话,让变压器进一步调用 visit _ * 挂钩:

  class RemoveFunctionCallAssignments(NodeTransformer):
删除形式为 target = name()的分配,因此将单个名称称为

目标列表大小不起作用。


def visit_Assign(自己,节点):
如果isinstance(node.value,ast.Call)和isinstance(node.value.func,ast.Name):
返回None
返回节点

此处,我们仅返回 None 如果赋值的值侧(右侧的表达式)是 Call 节点,该节点应用于简单的 Name 节点。返回传入的原始节点对象意味着它不会被替换。



要替换 toptop-level 函数调用(因此那些没有赋值或其他表达式),请查看 Expr 节点;这些是表达式 statements ,而不仅仅是属于其他某些构造的表达式。如果您有一个 Expr 节点且具有 Call ,则可以将其删除:

  def visit_Expr(self,node):
#如果是isinstance(node.value,则将删除对单个名称的独立调用
,ast.Call)和isinstance(node.value.func,ast.Name):
返回None
返回节点

另请参见出色的 绿树蛇文档,其中介绍了在AST树上的工作,并附有更多示例。 p>

For example if I wanted to change greater than to less than or equal to I have successfully executed:

def visit_Gt(self, node):
    new_node = ast.GtE()
    return ast.copy_location(new_node, node)

How would I visit/detect an assignment operation (=) and a function call () and simply delete them? I'm reading through the AST documentation and I can't find a way to visit the assignment or function call classes and then return nothing.

An example of what I'm seeking for assignment operations:

print("Start")
x = 5
print("End")

Becomes:

print("Start")

print("End")

And an example of what I'm seeking for deleting function calls:

 print("Start")
 my_function_call(Args)
 print("End")

Becomes

print("Start")

print("End")

解决方案

You can use a ast.NodeTransformer() subclass to mutate an existing AST tree:

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)

The above class removes None to completely remove the node from the input tree. The Assign and AugAssign nodes contain the whole assignment statement, so the expression producing the result, and the target list (1 or more names to assign the result to).

This means that the above will turn

print('Start!')
foo = 'bar'
foo += 'eggs'
print('Done!')

into

print('Start!')


print('Done!')

If you need to make more fine-grained decisions, look at the child nodes of the assignment, either directly, or by passing the child nodes to self.visit() to have the transformer further call visit_* hooks for them if they exist:

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

Here, we only return None if the value side of the assignment (the expression on the right-hand side) is a Call node that is applied to a straight-forward Name node. Returning the original node object passed in means that it'll not be replaced.

To replace top-level function calls (so those without an assignment or further expressions), look at Expr nodes; these are expression statements, not just expressions that are part of some other construct. If you have a Expr node with a Call, you can remove it:

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

Also see the excellent Green Tree Snakes documentation, which covers working on the AST tree with further examples.

这篇关于使用AST模块来更改和删除分配/函数调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆