将Python AST编译为方法

10 投票
1 回答
5695 浏览
提问于 2025-04-16 23:35

我最近在用Python玩AST(抽象语法树)。我想在程序运行时通过改变AST来修改方法。

我可以用inspect.getsource()获取一个预编译方法的源代码,并且可以通过AST访问器来按需要修改AST。

这可能有点天真,但我希望能编译这个AST,做类似这样的事情:

myClass.method.__func__.__code__ = compile(newAST, '<string>', 'exec')

不过,编译时只接受以ast.Module为根的AST。有没有办法只编译一个ast.FunctionDef,或者从编译后的(其他部分为空的)模块代码中获取函数的代码对象呢?

如果能给我一些关于这方面的信息就太好了。我看到的AST示例大多只处理简单的表达式。


我意识到我只需要在一个命名空间中执行这个模块,这样我就能访问到正常的结构了。所以模式是:

src = inspect.getsource(myClass.myMethod)
astFromSrc = ast.parse(unindent(src))         # need to remove extra indent from method
transform(astFromSrc.body)                    # transform the AST as you need 
ast.fix_missing_locations(astFromSrc)         # fix up line numbers etc
compiled = compile(astFromSrc, '<string>', 'exec') # compile the module AST

#######  From here is the part I was missing
myScope = {}                                  # make an empty namespace
exec compiled in myScope  # now myScope contains a proper compiled function

# Now replace the original with the modified version
myClass.myMethod.__func__.__code__ = myScope['myMethod'].__code__

但现在我有另一个问题:如何把这个过程融入到正常的Python构建流程中,这样修改只需要做一次,以后就可以从.pyc文件中加载?

1 个回答

1

你不应该在自己的回答里问新问题,而是应该单独提一个新问题。

注意,你的第一个和第二个问题有点矛盾。最开始你想在运行时做一些事情,后来又想把这些内容写入文件,这样就不用重复做了。请明确说明你的最终目标,这样我们才能清楚地知道你想要什么。

听起来你可以在修改了一个文件的抽象语法树(AST)后,创建一个新的 .py 文件,就像在解析一个 .py 文件,读取 AST,修改它,然后写回修改后的源代码中所解释的那样。

然后你可以通过编译新创建的 py 文件来获得你的 pyc 文件。

撰写回答