Wenn Sie es ausprobieren möchten, müssen Sie diese Python-Visualisierungsbibliothek installieren.
Pythons Ast-Bibliothek verfügt über eine Parse-Methode, die den eingehenden Inhalt in einen AST analysieren kann. Anschließend exportieren wir es mit ast.dump
und drucken es aus.
Hinweis: indent
Dieser Parameter ist erst nach Python 3.9 verfügbar. Wenn die Version früher ist, können Sie ihn entfernen, was sich nur auf das endgültige Ausgabeformat auswirkt. 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
Gut Ja, so einfach ist das. Wir haben das getan, weil diese Bibliothek sehr leistungsfähig ist, hier aber nur wenig genutzt wird. Tatsächlich ist die Grundstruktur hier bereits zu sehen, aber mein Ziel ist es, eine JSON-Darstellung dieses Baums zu generieren. Ich möchte die obige Python-Zeichenbibliothek zum Zeichnen verwenden. Die unterstützte Eingabe ist JSON und ihr Format ist:
rrreee🎜Rough Traversal Method🎜rrreee🎜Run results:data.json
. Ich finde es sehr interessant, die Ergebnisse direkt auf der Konsole auszugeben. pytm-cli -d TB -i data.json -o demo.html
demo.html
im Browser , das heißt Sie können den Effekt sehen. 🎜🎜🎜 🎜Mainstream Die Traversal-Methode🎜🎜Obwohl die obige Traversal-Methode leicht zu verstehen ist, ist es schwierig, sie zu erweitern. AST wird normalerweise über das Visitor-Muster durchlaufen, und die ast-Bibliothek bietet auch mehrere Traversierungsmethoden. ast.NodeVisitor
aus. Die Verwendung ist auch sehr einfach. Erben Sie einfach diese Klasse und schreiben Sie dann unterschiedliche Verarbeitungslogik für verschiedene Knoten (dies trennt die Logik verschiedener Knoten und verringert die Kopplung des Codes). 🎜🎜🎜 🎜Complete Die vorherige grobe Version des Codes 🎜rrreee🎜 begann direkt mit Expr
. Für diese elegantere Version habe ich auch den Knoten Module
hinzugefügt. 🎜🎜🎜🎜Das obige ist der detaillierte Inhalt vonSo realisieren Sie die Visualisierung des Syntaxbaums einfacher vier arithmetischer Operationen in Python. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!