Si vous voulez l'essayer, vous devez installer cette bibliothèque de visualisation Python.
La bibliothèque ast de Python dispose d'une méthode d'analyse qui peut analyser le contenu entrant dans un AST. Nous l'exportons ensuite en utilisant ast.dump
et l'imprimons.
Remarque : indent
Ce paramètre n'est disponible qu'après Python 3.9. Si la version est antérieure, vous pouvez le supprimer, ce qui n'affectera que le format de sortie final. ast.dump
将其导出并打印。
注意:indent
这个参数是 Python 3.9 以后才有的,如果版本低的话,可以去掉,只会影响最后输出的格式。
好了,就是这么简单。我们已经做到了,因为这个库的功能很强大,但是这里只是用到一点点而已。其实这里已经可以看出基本的结构了,不过我的目的是生成这棵树的 JSON 表示。我想要使用上面的 Python 绘图库把它绘制出来,它所支持的输入是 JSON,并且它的格式为:
{ "name": "A", "children": [ "name": "B", "children": [] ] }
""" Python's AST 利用 Python 的 ast 模块来解析表达式(简单的二元运算), 然后通过遍历语法树来生成 JSON 表示,再使用 PYthon 的库来 将其可视化。这个程序的目的是为了验证自己写的简易解析器是否正确。 """ import ast import json # 操作类型和操作符映射的字典 OPERATORS = { ast.Add: "+", ast.Sub: "-", ast.Mult: "*", ast.Div: "/" } def generate(tree: ast.Module): """ generate expression AST's representation of JSON """ if not tree: raise Exception("Emtpy AST tree!") if tree.__class__ == ast.Module: print(json.dumps({ "name": "Expr", "children": [DFS(tree.body[0].value)] # type: ignore }, indent=4)) def DFS(node): """ DFS AST """ if not node: return {} if node.__class__ == ast.BinOp: return { "name": "BinOp", "children": [ { "name": "left", "children": [ DFS(node.left) ] }, DFS(node.op), { "name": "left", "children": [ DFS(node.right) ] } ] } if node.__class__ == ast.Constant: return { "name": "NUMBER", "children": [ { "name": str(node.value) # Python 的绘图库,必须是字符串才能正常显示 } ] } if node.__class__ in [ast.Add, ast.Sub, ast.Mult, ast.Div]: return { "name": "Op", "children": [ { "name": OPERATORS[node.__class__] } ] } # 这里我只处理 加减乘除和数字类型的运行 raise Exception("There is not support extra type.") if __name__ == "__main__": ast_tree = ast.parse("1+2+3+4+5") print(ast.dump(ast_tree, indent=4)) generate(ast_tree)
运行结果:
我这里会输出两个东西,一个是 AST 的 dump;另一个是 AST 的 JSON 表示(逻辑结构的 JSON 表示,不是对象的 JSON 表示)。
把打印出来的 JSON 字符串复制进文件,命名为 data.json
。我感觉直接输出到控制台蛮有意思的,我喜欢直接看到它的结果。
执行如下命令:pytm-cli -d TB -i data.json -o demo.html
在浏览器打开 demo.html
即可看到效果了。
上面这种遍历方法虽然便于理解,但是难以扩展。AST 通常是通过 访问者模式 进行遍历的,而且 ast 库也提供了几种遍历方法。
因为这里只需要遍历来生成 JSON,并不需要修改AST本身,所以我们只看下面这两种即可。显然第一种是不能用的,原因已经用蓝色标记出来了。它自己说了如果你不关心上下文,因为生成 JSON 实际上是需要关注这个的。所以,我选择下面的 ast.NodeVisitor
。使用它也很简单,继承这个类,然后对不同的节点写不同的处理逻辑就行了(这样把不同节点的逻辑分开了,降低了代码的耦合性)。
""" Python's AST 利用 Python 的 ast 模块来解析表达式(简单的二元运算), 然后通过遍历语法树来生成 JSON 表示,再使用 PYthon 的库来 将其可视化。这个程序的目的是为了验证自己写的简易解析器是否正确。 """ import ast import json # 操作类型和操作符映射的字典 OPERATORS = { ast.Add: "+", ast.Sub: "-", ast.Mult: "*", ast.Div: "/" } class JSONVisitor(ast.NodeVisitor): """ JSON visitor: Traversal AST and generate JSON representation """ def visit_Module(self, node): module = { "name": "Module", "children": [] } for sub_node in node.body: module["children"].append(self.visit(sub_node)) return module def visit_Expr(self, node): return { "name": "Expr", "children": [ self.visit(node.value) ] } def visit_BinOp(self, node): return { "name": "BinOp", "children": [ { "name": "left", "children": [ self.visit(node.left) ] }, self.visit(node.op), { "name": "right", "children": [ self.visit(node.right) ] } ] } def visit_Constant(self, node): return { "name": "NUMBER", "children": [{ "name": str(node.value) # # Python 的绘图库,必须是字符串才能正常显示 }] } def visit_Add(self, node): return self.__visit(node) def visit_Sub(self, node): return self.__visit(node) def visit_Mult(self, node): return self.__visit(node) def visit_Div(self, node): return self.__visit(node) def __visit(self, node): return { "name": "Op", "children": [{ "name": OPERATORS[node.__class__] }] } if __name__ == "__main__": ast_tree = ast.parse("1+2+3+4+5") visitor = JSONVisitor() json_str = visitor.visit(ast_tree) print(json.dumps(json_str, indent=4))
前面那个粗糙版本是直接从 Expr
开始的,这个优雅点的版本,我就把 Module
Bien Oui, c'est aussi simple que cela. Nous l'avons fait parce que cette bibliothèque est très puissante, mais elle n'est que peu utilisée ici. En fait, la structure de base est déjà visible ici, mais mon objectif est de générer une représentation JSON de cet arbre. Je souhaite utiliser la bibliothèque de dessins Python ci-dessus pour le dessiner. L'entrée qu'elle prend en charge est JSON et son format est :
rrreee🎜Méthode de traversée approximative🎜rrreee🎜Exécuter les résultats :data.json
. Je trouve assez intéressant de sortir directement sur la console. J'aime voir les résultats directement. pytm-cli -d TB -i data.json -o demo.html
demo.html
dans le navigateur , c'est-à-dire que vous pouvez voir l'effet. 🎜🎜🎜 🎜Mainstream La méthode de traversée🎜🎜Bien que la méthode de traversée ci-dessus soit facile à comprendre, elle est difficile à développer. AST est généralement parcouru via le modèle de visiteur, et la bibliothèque ast fournit également plusieurs méthodes de parcours. ast.NodeVisitor
ci-dessous. Son utilisation est également très simple. Il suffit d'hériter de cette classe, puis d'écrire une logique de traitement différente pour différents nœuds (cela sépare la logique des différents nœuds et réduit le couplage du code). 🎜🎜🎜 🎜Complete La version précédente approximative du code 🎜rrreee🎜 démarrait directement à partir de Expr
. Pour cette version plus élégante, j'ai également ajouté le nœud Module
. 🎜🎜🎜🎜Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!