网约车后台平台网站建设,设计官网需要留言吗,室内装修设计软件下载,网页制作300字心得目录 基本概念节点类型ast.Assignast.Nameast.Constantast.Callast.Attribute 结点的遍历ast源码示例 结点的修改示例 参考链接 基本概念
在 python 中#xff0c;我们可以通过自带的 ast 模块来对解析遍历语法树#xff0c;通过ast.parse()可以将字符串代码解析为抽象语法树… 目录 基本概念节点类型ast.Assignast.Nameast.Constantast.Callast.Attribute 结点的遍历ast源码示例 结点的修改示例 参考链接 基本概念
在 python 中我们可以通过自带的 ast 模块来对解析遍历语法树通过ast.parse()可以将字符串代码解析为抽象语法树然后通过ast.dump()可以打印这棵语法树。 除了ast模块外还有 astor 模块其中的 astor.to_sourse() 函数可以将语法树Node转换为代码 astor.dump_tree() 可以很好地格式化整棵树。 除了这些基础操作外我们还可以遍历和修改整棵语法树。 比如对于a 10 来说我们可以先解析成抽象语法树然后打印所有的结点如下所示。根据输出我们可以看到根节点是Module类型的然后其body是Assign类型的。对于Assign类型的结点可以继续划分为Name结点表示变量名和Constant结点表示变量内容。
node ast.parse(a 10)
print(astor.dump_tree(node))
# Module(body[Assign(targets[Name(ida)], valueConstant(value10, kindNone), type_commentNone)], type_ignores[])节点类型
上面的简单示例向我们展示了几种基本结点类型Assign、Name、Constant接下来我们将会展示其他几种常见的结点类型和示例完整的节点类型可以查阅节点类型。大体上我们可以把结点类型分为叶子结点类型和非叶子结点类型比如Assign就是非叶子结点类型Name和Constant是叶子结点类型因为他们不会有子结点了。
ast.Assign
Assign 类型用来表示赋值语句比如a 10、 b a 这样的赋值语句都是Assign结点类型他并不是一个叶子结点因为它的下面一般还有 Name 结点。
ast.Name
Name类型用来表示一个变量的名称是一个叶子结点。比如对于b a 这样的赋值语句子结点就是两个Name。
node ast.parse(a b)
print(astor.dump_tree(node.body[0]))
# Assign(targets[Name(ida)], valueName(idb), type_commentNone)ast.Constant
表示一个不可变内容它可以是Number 、string只要其内容是不可变的都是ast.Constant类型的结点它是一个叶子结点。
node ast.parse(a 100)
print(astor.dump_tree(node.body[0]))
# Assign(targets[Name(ida)], valueConstant(value100, kindNone), type_commentNone)node ast.parse(a paddle)
print(astor.dump_tree(node.body[0]))
# Assign(targets[Name(ida)], valueConstant(valuepaddle, kindNone), type_commentNone)ast.Call
表示函数的调用比如paddle.to_tensor()。非叶子节点类型一般包含三个属性func、args、 keywords。
func代表调用函数的名称一般是一个ast.Name或ast.Constant类型的结点如果是连续调用会是一个ast.Call结点。args代表函数传入的位置参数和可变参数。keywords代表函数传入的关键字参数。
node ast.parse(paddle.to_tensor(1, a 10))
print(astor.dump_tree(node.body[0]))# Expr(valueCall(funcAttribute(valueName(idpaddle), attrto_tensor),args[Constant(value1, kindNone)],keywords[keyword(arga, valueConstant(value10, kindNone))]))对于上面的例子我们通过可视化可以看到顶层是一个ast.Expr类型的结点表示一个表达式。下面是ast.Call 结点Call 结点包含 一个ast.Attribute结点表示调用者和调用的方法名paddle是调用者to_tensor是方法名一个ast.Constant类型的args表示函数的位置参数一个ast.keyword表示函数的关键字参数。 下面我们看一个比较复杂的示例多个函数的连续调用。根据输出结果可以看到最后的调用reshape在最外层然后一直向内递归子结点还是ast.Call类型的结点。
node ast.parse(a.to_tensor(1, a 10).reshape(1))
print(astor.dump_tree(node.body[0]))Expr(valueCall(funcAttribute(valueCall(funcAttribute(valueName(ida), attrto_tensor), args[Constant(value1, kindNone)],keywords[keyword(arga, valueConstant(value10, kindNone))]),attrreshape),args[Constant(value1, kindNone)],keywords[]))ast.Attribute
上面的例子中出现了ast.Attribute结点Attribute结点可以理解为属性是一个非叶子结点。它包含两个字段value字段和attr字段。对于a.shape来说value指明调用者即aattr指明调用的方法名即shape。
node ast.parse(a.shape)
print(astor.dump_tree(node.body[0]))Expr(valueAttribute(valueName(ida), attrshape))结点的遍历
在ast模块中可以借助继承ast.NodeVisitor类来完成结点的遍历该类具有两种访问结点的方法一种是针对所有结点类型通用的访问方法generic_visit()另一种是针对某个类型结点的访问方法 visit_xxx其中xxx代表具体的结点类型。generic_visit()函数是遍历每个结点的入口函数随后会调用visitor()函数获取该结点的类型然后判断是否有遍历该类型结点的函数如果有则调用 visit_xxx类型的方法如果没有则调用通用generic_visit()方法。
ast源码
class NodeVisitor(object):def visit(self, node):Visit a node.method visit_ node.__class__.__name__visitor getattr(self, method, self.generic_visit)return visitor(node)def generic_visit(self, node):# 可以看到 generic_visit函数会调用visit函数然后寻找并调用特定类型的visit函数。 Called if no explicit visitor function exists for a node.for field, value in iter_fields(node):if isinstance(value, list):for item in value:if isinstance(item, AST):self.visit(item)elif isinstance(value, AST):self.visit(value)def visit_Constant(self, node):value node.valuetype_name _const_node_type_names.get(type(value))if type_name is None:for cls, name in _const_node_type_names.items():if isinstance(value, cls):type_name namebreakif type_name is not None:method visit_ type_nametry:visitor getattr(self, method)except AttributeError:passelse:import warningswarnings.warn(f{method} is deprecated; add visit_Constant,PendingDeprecationWarning, 2)return visitor(node)return self.generic_visit(node)示例
下面是一个例子我们定义了一个继承ast.NodeVisitor的类并且重写了visit_attribute方法这样在遍历到ast.Attribute结点时会输出当前调用的属性名或方法名对于其他类型的结点则会输出结点类型。
class CustomVisitor(ast.NodeVisitor):def visit_Attribute(self, node):print(---- node.attr)ast.NodeVisitor.generic_visit(self, node)def generic_visit(self, node):print(node.__class__.__name__)ast.NodeVisitor.generic_visit(self, node)code textwrap.dedent(import paddlex paddle.to_tensor([1, 2, 3])axis 0y paddle.max(x, axisaxis)
)
node ast.parse(code)
visitor CustomVisitor()
visitor.generic_visit(node)需要注意的是当我们重写visit_xxx函数后一定要记得再次调用ast.NodeVisitor.generic_visit(self, node)这样才会继续遍历整棵语法树。 结点的修改
对于结点的修改可以借助ast.NodeTransformer 类来完成ast.NodeTransformer继承自ast.NodeVisitor类重写了generic_visit方法该方法可以传入一个结点并且返回修改后的结点从而完成语法树的修改。
示例
在该示例中我们定义了CustomVisitor类来修改ast.Call 结点。具体来说当遍历到Call类型的结点后流程如下
首先会调用get_full_attr方法获取整个api名称如果是普通方法调用则会返回完整的调用名称比如torch.tensor()会返回torch.tensor如果是连续的方法调用比如x.exp().floor()则会返回ClassMethod.floor。然后调用 ast.NodeVisitor.generic_visit(self, node) 进行深度优先的修改这样就可以一层层递归先修改内层再修改外层。如果是普通的方法调用则修改结点后返回如果是连续的方法调用需要先通过astor.to_source(node)获取前缀方法即调用者保留前缀方法名称的同时修改目前的方法名后返回。具体是通过{}.{}()实现的。
def get_full_attr(node):# torch.nn.fucntional.reluif isinstance(node, ast.Attribute):return get_full_attr(node.value) . node.attr# x.abs() - xelif isinstance(node, ast.Name):return node.id# for example ast.Callelse:return ClassMethodclass CustomVisitor(ast.NodeTransformer):def visit_Call(self, node):# 获取api的全称full_func get_full_attr(node.func)# post orderast.NodeVisitor.generic_visit(self, node)# 如果是普通方法调用直接改写整个结点即可if full_func torch.tensor:# 将 torch.tensor() 改写为 paddle.to_tensor()code paddle.to_tensor()new_node ast.parse(code).body[0]return new_node.value# 如果是类方法调用需要取前面改写后的方法作为 func.value if full_func ClassMethod.floor:# 获取前缀方法作为 func.valuenew_func astor.to_source(node).strip(\n)new_func new_func[0: new_func.rfind(.)]# 将 floor() 改写为 floor2()code {}.{}().format(new_func, floor2)new_node ast.parse(code).body[0]return new_node.value# 其余结点不修改return nodecode textwrap.dedent(import torchx torch.tensor([1, 2, 3])x x.exp().floor()
)
node ast.parse(code)
visitor CustomVisitor()
node visitor.generic_visit(node)
result_code astor.to_source(node)
print(result_code)参考链接
https://blog.csdn.net/ThinkTimes/article/details/110831176?ydrefereraHR0cHM6Ly9jbi5iaW5nLmNvbS8%3D https://greentreesnakes.readthedocs.io/en/latest/ https://github.com/PaddlePaddle/PaConvert 文章转载自: http://www.morning.jhrlk.cn.gov.cn.jhrlk.cn http://www.morning.xtkw.cn.gov.cn.xtkw.cn http://www.morning.splkk.cn.gov.cn.splkk.cn http://www.morning.cbndj.cn.gov.cn.cbndj.cn http://www.morning.smszt.com.gov.cn.smszt.com http://www.morning.wfttq.cn.gov.cn.wfttq.cn http://www.morning.rrjzp.cn.gov.cn.rrjzp.cn http://www.morning.yixingshengya.com.gov.cn.yixingshengya.com http://www.morning.dnzyx.cn.gov.cn.dnzyx.cn http://www.morning.sbjbs.cn.gov.cn.sbjbs.cn http://www.morning.gwqq.cn.gov.cn.gwqq.cn http://www.morning.gpkjx.cn.gov.cn.gpkjx.cn http://www.morning.bfgpn.cn.gov.cn.bfgpn.cn http://www.morning.cgthq.cn.gov.cn.cgthq.cn http://www.morning.c7496.cn.gov.cn.c7496.cn http://www.morning.rhzzf.cn.gov.cn.rhzzf.cn http://www.morning.btqrz.cn.gov.cn.btqrz.cn http://www.morning.jsrnf.cn.gov.cn.jsrnf.cn http://www.morning.kmlmf.cn.gov.cn.kmlmf.cn http://www.morning.lqchz.cn.gov.cn.lqchz.cn http://www.morning.glrzr.cn.gov.cn.glrzr.cn http://www.morning.huxinzuche.cn.gov.cn.huxinzuche.cn http://www.morning.mxnhq.cn.gov.cn.mxnhq.cn http://www.morning.mwmxs.cn.gov.cn.mwmxs.cn http://www.morning.wfbnp.cn.gov.cn.wfbnp.cn http://www.morning.drndl.cn.gov.cn.drndl.cn http://www.morning.ydnxm.cn.gov.cn.ydnxm.cn http://www.morning.gfrtg.com.gov.cn.gfrtg.com http://www.morning.rddlz.cn.gov.cn.rddlz.cn http://www.morning.qhqgk.cn.gov.cn.qhqgk.cn http://www.morning.smspc.cn.gov.cn.smspc.cn http://www.morning.hmqmm.cn.gov.cn.hmqmm.cn http://www.morning.dzpnl.cn.gov.cn.dzpnl.cn http://www.morning.snkry.cn.gov.cn.snkry.cn http://www.morning.dztp.cn.gov.cn.dztp.cn http://www.morning.c7495.cn.gov.cn.c7495.cn http://www.morning.ljfjm.cn.gov.cn.ljfjm.cn http://www.morning.gkfwp.cn.gov.cn.gkfwp.cn http://www.morning.jtfsd.cn.gov.cn.jtfsd.cn http://www.morning.rlpmy.cn.gov.cn.rlpmy.cn http://www.morning.xjqrn.cn.gov.cn.xjqrn.cn http://www.morning.dnydy.cn.gov.cn.dnydy.cn http://www.morning.qrsrs.cn.gov.cn.qrsrs.cn http://www.morning.zxznh.cn.gov.cn.zxznh.cn http://www.morning.xxwfq.cn.gov.cn.xxwfq.cn http://www.morning.hrpbq.cn.gov.cn.hrpbq.cn http://www.morning.mfct.cn.gov.cn.mfct.cn http://www.morning.nsmyj.cn.gov.cn.nsmyj.cn http://www.morning.wcqxj.cn.gov.cn.wcqxj.cn http://www.morning.pycpt.cn.gov.cn.pycpt.cn http://www.morning.sfhjx.cn.gov.cn.sfhjx.cn http://www.morning.pbsqr.cn.gov.cn.pbsqr.cn http://www.morning.mwmxs.cn.gov.cn.mwmxs.cn http://www.morning.ghxkm.cn.gov.cn.ghxkm.cn http://www.morning.kdlzz.cn.gov.cn.kdlzz.cn http://www.morning.fjgwg.cn.gov.cn.fjgwg.cn http://www.morning.mqwnz.cn.gov.cn.mqwnz.cn http://www.morning.txfxy.cn.gov.cn.txfxy.cn http://www.morning.wqpb.cn.gov.cn.wqpb.cn http://www.morning.qfqld.cn.gov.cn.qfqld.cn http://www.morning.gzzncl.cn.gov.cn.gzzncl.cn http://www.morning.hctgn.cn.gov.cn.hctgn.cn http://www.morning.kksjr.cn.gov.cn.kksjr.cn http://www.morning.bkcnq.cn.gov.cn.bkcnq.cn http://www.morning.lwyqd.cn.gov.cn.lwyqd.cn http://www.morning.khxyx.cn.gov.cn.khxyx.cn http://www.morning.kbdrq.cn.gov.cn.kbdrq.cn http://www.morning.fmgwx.cn.gov.cn.fmgwx.cn http://www.morning.psyrz.cn.gov.cn.psyrz.cn http://www.morning.sbrxm.cn.gov.cn.sbrxm.cn http://www.morning.dtnzk.cn.gov.cn.dtnzk.cn http://www.morning.xtgzp.cn.gov.cn.xtgzp.cn http://www.morning.pyxwn.cn.gov.cn.pyxwn.cn http://www.morning.xkjrq.cn.gov.cn.xkjrq.cn http://www.morning.kwqwp.cn.gov.cn.kwqwp.cn http://www.morning.baohum.com.gov.cn.baohum.com http://www.morning.rwhlf.cn.gov.cn.rwhlf.cn http://www.morning.qkdjq.cn.gov.cn.qkdjq.cn http://www.morning.shyqcgw.cn.gov.cn.shyqcgw.cn http://www.morning.wgrl.cn.gov.cn.wgrl.cn