将python对象转换为python AST节点

时间:2017-04-23 18:47:26

标签: python code-generation

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

我想要的用法示例,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)

请帮助我找到some_magic

1 个答案:

答案 0 :(得分:2)

没有办法做你想做的事,因为这不是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

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

现在,m.x的值是228,但是没有办法知道导致该值的表达式是什么(好吧,没有读取__main__.py的AST但是这会很快失控)。它只是字面上的吗?函数调用的结果?

如果在修改模块的某个值后确实需要获得新的AST,最好的解决方案是自己转换原始AST。 您可以找到您的标识符获取其值的位置,并将该任务的值替换为您想要的任何值。 例如,在我的小例子中,x = 0由以下AST表示:

Assign(targets=[Name(id='x', ctx=Store())], value=Num(n=0))

为了使AST符合我在__main__.py中所做的重新分配,我必须更改上述{​​{1}}节点的值,如下所示:

Assign

如果您想这样做,我建议您查看Python的AST节点转换器文档(ast.NodeTransformer),以及记录您在Python ASTs中可以遇到的所有节点的优秀手册{ {3}}