将 python 对象转换为 python AST-nodes

Vla*_*mir 3 python code-generation

我需要将修改后的 python 对象转储回源代码。所以我尝试找到一些东西将真正的python对象转换为python ast.Node(稍后在astorlib中使用以转储源代码)

我想要的用法示例,Python 2:

import ast
import importlib

import astor


m = importlib.import_module('something')

# modify an object
m.VAR.append(123)

ast_nodes = some_magic(m)

source = astor.dump(ast_nodes)
Run Code Online (Sandbox Code Playgroud)

请帮我找到那个 some_magic

Alv*_*vae 6

没有办法做你想做的事,因为这不是 AST 的工作方式。当解释器运行您的代码时,它将从源文件中生成一个 AST,并解释该 AST 以生成 python 对象。这些对象生成后会发生什么与 AST 无关。

然而,可以首先获得生成对象的 AST。该模块inspect可让您获取一些 Python 对象的源代码:

import ast
import importlib
import inspect

m = importlib.import_module('pprint')
s = inspect.getsource(m)
a = ast.parse(s)
print(ast.dump(a))
# Prints the AST of the pprint module
Run Code Online (Sandbox Code Playgroud)

getsource()名字恰如其分。如果我要更改 中某个变量(或任何其他对象)的值m,它不会更改其源代码。

即使可以从对象中重新生成 AST,也不会some_magic()返回单个解决方案。想象一下,我x在某个模块中有一个变量,我在另一个模块中重新分配了该变量:

# In some_module.py
x = 0

# In __main__.py
m = importlib.import_module('some_module')
m.x = 1 + 227
Run Code Online (Sandbox Code Playgroud)

现在, 的值为m.xis 228,但无法知道是哪种表达式导致了该值(好吧,不阅读 的 AST__main__.py但这很快就会失控)。仅仅是字面意思吗?函数调用的结果?

如果在修改某个模块的某些值后确实必须获得新的 AST,最好的解决方案是自己转换原始 AST。你可以找到你的标识符从哪里得到它的值,并用你想要的任何值替换分配的值。例如,在我的小例子x = 0中由以下 AST 表示:

Assign(targets=[Name(id='x', ctx=Store())], value=Num(n=0))
Run Code Online (Sandbox Code Playgroud)

为了使 AST 与我在 中所做的重新分配相匹配__main__.py,我必须将上述Assign节点的值更改为如下所示:

value=BinOp(left=Num(n=1), op=Add(), right=Num(n=227))
Run Code Online (Sandbox Code Playgroud)

如果您想这样做,我建议您查看 Python 的 AST 节点转换器 ( ast.NodeTransformer ) 文档,以及这本出色的手册,其中记录了您可以在 Python AST 中遇到的所有节点Green Tree Snakes - the missing Python AST 文档