使用 ast 模块转换 Python 源中的随机常量

using ast module to transform random constants in Python source

我有兴趣编写一个程序,使用 Python 的内置 AST module 随机修改任意 Python 源中的常量。

此转换可能涉及使用 AST 模块定义的操作遍历抽象语法树表示。该模块提供了两个选项:首先,ast.walk() returns references to all nodes in the AST, but does not offer any contextual information, making reassembling the tree impossible. Secondly, the documentation describes a second method involving the ast.NodeTransformer class: several sources of documentation 大致描述了如何使用 NodeTransformer。

但是,NodeTransformer 文档没有提及如何将条件替换随机应用于 AST。具体来说,我想修改此功能以创建一个函数,该函数 在 ast 中选择一个随机节点,随机选择一个与该节点关联的常量,并用随机选择的相同类型的常量替换该常量.

我怀疑我很难理解如何正确修改 NodeTransformer,因为我很少以面向对象的风格(通常坚持函数式范例)进行编程。希望你们中的一个人能很容易地为我指明正确的方向。

如果您只想随机修改常量,那么您实际上并不需要节点上下文。您可以遍历树寻找常量节点,如果看到一个,则更改其值。这是一个简单的例子:

source = """
x = 2
"""

# exec the source as-is
mod = {}
exec compile(source, '<blah>', 'exec') in mod

print(mod['x'])
# prints 2

t = ast.parse(source)
# change all numerical constants to 8
for node in ast.walk(t):
    if isinstance(node, ast.Num):
        node.n = 8
# exec the modified AST
modMod = {}
exec compile(t, '<blah>', 'exec') in modMod

print(modMod['x'])
# prints 8

如果你想随机选择是否修改一个常量,你也可以这样做。我不确定我是否理解你关于选择 "a random node in the AST" 的问题陈述。 AST 的分层性质意味着随机节点可以是从单个常量到整个模块的任何东西,因此首先选择一个随机节点然后选择其中的常量节点似乎有点奇怪。为什么不首先选择一个随机常量节点?