如何将 python 代码转换为解析树并返回原始代码?
How can I convert python code into a parse tree and back into the original code?
我希望能够将 python 代码(字符串)转换为解析树,在树级别对其进行修改,然后将树转换为代码(字符串)。当转换为解析树并返回代码时没有任何树级修改,生成的代码应该与原始输入代码完全匹配。
我想为此使用 python。我找到了 ast
和 parser
python 模块,但是 ast 树丢失了有关原始代码的信息。至于 parser
模块,我似乎无法弄清楚如何操作解析树或将其转换为代码。
这是我目前的情况。
import ast
import astor # pip install astor
import parser
code = 'hi = 0'
ast_tree = ast.parse(code)
code_from_ast = astor.to_source(tree) # 'hi = 0\n'
parser_tree = parser.suite(code)
code_from_parser = ???
如您所述,内置的 ast
模块不会保留很多格式信息(空格、注释等)。
在这种情况下,您需要具体语法树(例如 LibCST)而不是抽象语法树。 (可以通过pip install libcst
安装)
这里是一个示例,展示了如何将代码从 hi = 0
更改为 hi = 2
,方法是将代码解析为树、改变树并将树渲染回源代码。
可以在 https://libcst.readthedocs.io/
中找到更高级的用法
In [1]: import libcst as cst
In [2]: code = 'hi = 0'
In [3]: tree = cst.parse_module(code)
In [4]: print(tree)
Module(
body=[
SimpleStatementLine(
body=[
Assign(
targets=[
AssignTarget(
target=Name(
value='hi',
lpar=[],
rpar=[],
),
whitespace_before_equal=SimpleWhitespace(
value=' ',
),
whitespace_after_equal=SimpleWhitespace(
value=' ',
),
),
],
value=Integer(
value='0',
lpar=[],
rpar=[],
),
semicolon=MaybeSentinel.DEFAULT,
),
],
leading_lines=[],
trailing_whitespace=TrailingWhitespace(
whitespace=SimpleWhitespace(
value='',
),
comment=None,
newline=Newline(
value=None,
),
),
),
],
header=[],
footer=[],
encoding='utf-8',
default_indent=' ',
default_newline='\n',
has_trailing_newline=False,
)
In [5]: class ModifyValueVisitor(cst.CSTTransformer):
...: def leave_Assign(self, node, updated_node):
...: return updated_node.with_changes(value=cst.Integer(value='2'))
...:
In [6]: modified_tree = tree.visit(ModifyValueVisitor())
In [7]: modified_tree.code
Out[7]: 'hi = 2'
我希望能够将 python 代码(字符串)转换为解析树,在树级别对其进行修改,然后将树转换为代码(字符串)。当转换为解析树并返回代码时没有任何树级修改,生成的代码应该与原始输入代码完全匹配。
我想为此使用 python。我找到了 ast
和 parser
python 模块,但是 ast 树丢失了有关原始代码的信息。至于 parser
模块,我似乎无法弄清楚如何操作解析树或将其转换为代码。
这是我目前的情况。
import ast
import astor # pip install astor
import parser
code = 'hi = 0'
ast_tree = ast.parse(code)
code_from_ast = astor.to_source(tree) # 'hi = 0\n'
parser_tree = parser.suite(code)
code_from_parser = ???
如您所述,内置的 ast
模块不会保留很多格式信息(空格、注释等)。
在这种情况下,您需要具体语法树(例如 LibCST)而不是抽象语法树。 (可以通过pip install libcst
安装)
这里是一个示例,展示了如何将代码从 hi = 0
更改为 hi = 2
,方法是将代码解析为树、改变树并将树渲染回源代码。
可以在 https://libcst.readthedocs.io/
In [1]: import libcst as cst
In [2]: code = 'hi = 0'
In [3]: tree = cst.parse_module(code)
In [4]: print(tree)
Module(
body=[
SimpleStatementLine(
body=[
Assign(
targets=[
AssignTarget(
target=Name(
value='hi',
lpar=[],
rpar=[],
),
whitespace_before_equal=SimpleWhitespace(
value=' ',
),
whitespace_after_equal=SimpleWhitespace(
value=' ',
),
),
],
value=Integer(
value='0',
lpar=[],
rpar=[],
),
semicolon=MaybeSentinel.DEFAULT,
),
],
leading_lines=[],
trailing_whitespace=TrailingWhitespace(
whitespace=SimpleWhitespace(
value='',
),
comment=None,
newline=Newline(
value=None,
),
),
),
],
header=[],
footer=[],
encoding='utf-8',
default_indent=' ',
default_newline='\n',
has_trailing_newline=False,
)
In [5]: class ModifyValueVisitor(cst.CSTTransformer):
...: def leave_Assign(self, node, updated_node):
...: return updated_node.with_changes(value=cst.Integer(value='2'))
...:
In [6]: modified_tree = tree.visit(ModifyValueVisitor())
In [7]: modified_tree.code
Out[7]: 'hi = 2'