【问题标题】:Edit attribute in script string with AST使用 AST 编辑脚本字符串中的属性
【发布时间】:2022-11-23 09:40:51
【问题描述】:

我不熟悉 AST 模块,如果有任何见解,我将不胜感激。例如,如果我有一个细绳包含有效的 python 脚本,例如

import sys #Just any module
class SomeClass:
    def __init__(self):
        self.x = 10
        self.b = 15
    def a_func(self):
        print(self.x)

我希望能够以编程方式编辑行,例如将 self.x = 10 更改为 self.x = 20 之类的内容。我可以通过 ast 将其分解:

some_string = "..." #String of class above
for body_item in ast.parse(some_string):
    ...

但这感觉不像是“正确”的方式(不是说有正确的方式,因为这有点小众)。我希望有人能纠正我更清洁,或者更好的东西。

【问题讨论】:

    标签: python metaprogramming abstract-syntax-tree


    【解决方案1】:

    您可以从使用 ast.dump 开始了解您正在处理的代码的 AST 结构:

    import ast
    
    code='self.x = 10'
    print(ast.dump(ast.parse(code), indent=2))
    

    这输出:

    Module(
      body=[
        Assign(
          targets=[
            Attribute(
              value=Name(id='self', ctx=Load()),
              attr='x',
              ctx=Store())],
          value=Constant(value=10))],
      type_ignores=[])
    

    从中你可以看到你想要寻找的是Assign节点,其中targets的第一个是Attribute节点,其valueName节点,id'self''x' 中的一个 attr

    有了这些知识,你就可以使用ast.walk遍历AST节点来寻找具有上述属性的节点,将其value修改为Constant节点,value20,最后使用ast.unparse 将 AST 转换回一串代码:

    import ast
    
    code = '''
    import sys #Just any module
    class SomeClass:
        def __init__(self):
            self.x = 10
            self.b = 15
        def a_func(self):
            print(self.x)
    '''
    tree = ast.parse(code)
    for node in ast.walk(tree):
        if (
            isinstance(node, ast.Assign) and
            isinstance((target := node.targets[0]), ast.Attribute) and
            isinstance(target.value, ast.Name) and
            target.value.id == 'self' and
            target.attr == 'x'
        ):
            node.value = ast.Constant(value=20)
    print(ast.unparse(tree))
    

    这输出:

    class SomeClass:
    
        def __init__(self):
            self.x = 20
            self.b = 15
    
        def a_func(self):
            print(self.x)
    

    请注意,ast.unparse 需要 Python 3.10 或更高版本。如果您使用的是早期版本,则可以改用 astunparse package 中的 astunparse.unparse

    演示:https://trinket.io/python3/3b09901326

    【讨论】:

    • 惊人的答案,正是我正在寻找的。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2012-01-26
    • 2021-02-03
    • 1970-01-01
    • 2011-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-24
    相关资源
    最近更新 更多