我想以编程方式编辑python源代码。基本上我想读取一个.py文件,生成AST,然后写回修改后的python源代码(即另一个.py文件)。
有一些方法可以使用标准的python模块(如ast或compiler)来解析/编译python源代码。但是,我认为它们都不支持修改源代码的方法(例如删除这个函数声明),然后再写回修改的python源代码。
更新:我想这样做的原因是我想为python写一个突变测试库,主要是通过删除语句/表达式,重新运行测试,看看有什么破坏。
我想以编程方式编辑python源代码。基本上我想读取一个.py文件,生成AST,然后写回修改后的python源代码(即另一个.py文件)。
有一些方法可以使用标准的python模块(如ast或compiler)来解析/编译python源代码。但是,我认为它们都不支持修改源代码的方法(例如删除这个函数声明),然后再写回修改的python源代码。
更新:我想这样做的原因是我想为python写一个突变测试库,主要是通过删除语句/表达式,重新运行测试,看看有什么破坏。
当前回答
内置ast模块似乎没有转换回源代码的方法。但是,这里的codegen模块为ast提供了一个漂亮的打印机,使您能够这样做。 如。
import ast
import codegen
expr="""
def foo():
print("hello world")
"""
p=ast.parse(expr)
p.body[0].body = [ ast.parse("return 42").body[0] ] # Replace function body with "return 42"
print(codegen.to_source(p))
这将打印:
def foo():
return 42
请注意,您可能会丢失确切的格式和注释,因为这些没有保留。
但是,您可能不需要这样做。如果您所需要的只是执行替换的AST,那么只需在AST上调用compile()并执行结果代码对象即可。
其他回答
内置ast模块似乎没有转换回源代码的方法。但是,这里的codegen模块为ast提供了一个漂亮的打印机,使您能够这样做。 如。
import ast
import codegen
expr="""
def foo():
print("hello world")
"""
p=ast.parse(expr)
p.body[0].body = [ ast.parse("return 42").body[0] ] # Replace function body with "return 42"
print(codegen.to_source(p))
这将打印:
def foo():
return 42
请注意,您可能会丢失确切的格式和注释,因为这些没有保留。
但是,您可能不需要这样做。如果您所需要的只是执行替换的AST,那么只需在AST上调用compile()并执行结果代码对象即可。
我们也有类似的需求,这里的其他答案并没有解决这个问题。因此,我们为此创建了一个库ASTTokens,它采用AST或astroid模块生成的AST树,并用原始源代码中的文本范围标记它。
它不直接修改代码,但在上面添加代码并不难,因为它会告诉您需要修改的文本范围。
例如,这将在WRAP(…)中包装一个函数调用,保留注释和其他内容:
example = """
def foo(): # Test
'''My func'''
log("hello world") # Print
"""
import ast, asttokens
atok = asttokens.ASTTokens(example, parse=True)
call = next(n for n in ast.walk(atok.tree) if isinstance(n, ast.Call))
start, end = atok.get_text_range(call)
print(atok.text[:start] + ('WRAP(%s)' % atok.text[start:end]) + atok.text[end:])
生产:
def foo(): # Test
'''My func'''
WRAP(log("hello world")) # Print
希望这能有所帮助!
花了一些时间,但是Python 3.9有这个: https://docs.python.org/3.9/whatsnew/3.9.html#ast https://docs.python.org/3.9/library/ast.html#ast.unparse
ast.unparse(ast_obj)
取消解析ast.AST对象并生成一个字符串,如果使用ast.parse()进行解析,该字符串将生成一个等效的ast.AST对象。
Pythoscope对它自动生成的测试用例执行此操作,就像python 2.6的2to3工具一样(它转换python 2。X源代码转换为python 3。x源)。
这两个工具都使用lib2to3库,它是python解析器/编译器机制的实现,可以在从source -> AST -> source循环绊倒源代码时保留源代码中的注释。
如果您想进行更多的重构(如转换),rope项目可以满足您的需求。
ast模块是另一个选择,还有一个关于如何将语法树“解解析”回代码的旧示例(使用解析器模块)。但是ast模块在对随后转换为代码对象的代码进行ast转换时更有用。
红男爵计划也可能是个不错的选择(泽维尔·康贝尔)
如果你在2019年看到这个,那么你可以使用这个libcst 包中。它的语法类似ast。这就像一个魅力,并保留了代码结构。这对于你必须保留注释、空格、换行符等的项目是很有帮助的。
如果您不需要关心保留注释、空格和其他内容,那么ast和astor的组合可以很好地工作。