Python AST到字典结构

时间:2016-10-04 04:33:43

标签: python json abstract-syntax-tree

我正在使用Python ast模块来解析像X >= 13 and Y == W这样的表达式。我需要的是在下面的预订字典中转换这个表达式:

{
  "function": "and",
  "args": [
    {
      "function": ">=",
      "args": [
        {
          "variable": "X"
        },
        {
          "value": 13
        }
      ]
    },
    {
      "function": "==",
      "args": [
        {
          "variable": "Y"
        },
        {
          "variable": "W"
        }
      ]
    }
  ]
}

Python AST为我提供了从值验证语法和差异变量的好处。以下代码进行了基本的解析,但注意输出不是预订的,我不完全确定如何处理:

import ast
class ExclusionParser(ast.NodeVisitor):
    tree = ''

    def append(self, expr):
        self.tree += expr

    def visit_And(self, node):
        self.append("and ")

    def visit_Lt(self, node):
        self.append("< ")

    def visit_Gt(self, node):
        self.append("> ")

    def visit_Eq(self, node):
        self.append("== ")

    def visit_Num(self, node):
        self.append("value: %s " % node.n)

    def visit_Name(self, node):
        self.append("variable: %s " % node.id)

    def generic_visit(self, node):
        """Called if no explicit visitor function exists for a node."""
        self.append("(")
        for field, value in ast.iter_fields(node):
            if isinstance(value, list):
                for item in value:
                    if isinstance(item, ast.AST):
                        self.visit(item)
            elif isinstance(value, ast.AST):
                self.visit(value)
        self.append(")")

if __name__ == '__main__':
    v = ExclusionParser()
    p = ast.parse("X > 13 and Y == W")
    v.visit(p)
    print(v.tree)

输出

(((and (variable: X > value: 13 )(variable: Y == variable: W ))))

1 个答案:

答案 0 :(得分:1)

考虑这些小改动 - 我已经添加了'和逗号:

import ast
class ExclusionParser(ast.NodeVisitor):
    tree = ''

    def append(self, expr):
        self.tree += expr

    def visit_And(self, node):
        self.append("'func:and', ")

    def visit_Lt(self, node):
        self.append("'func:lt', ")

    def visit_Gt(self, node):
        self.append("'func:gt', ")

    def visit_Eq(self, node):
        self.append("'func:eq', ")

    def visit_Num(self, node):
        self.append("'value:%s', " % node.n)

    def visit_Name(self, node):
        self.append("'variable:%s', " % node.id)

    def generic_visit(self, node):
        """Called if no explicit visitor function exists for a node."""
        self.append("[")
        for field, value in ast.iter_fields(node):
            if isinstance(value, list):
                for item in value:
                    if isinstance(item, ast.AST):
                        self.visit(item)
            elif isinstance(value, ast.AST):
                self.visit(value)
        self.append("], ")


if __name__ == '__main__':
    v = ExclusionParser()
    p = ast.parse("X > 13 and Y == W")
    v.visit(p)
    tree = ast.literal_eval(v.tree[:-2])
    print(tree)

此时tree是有效列表:

[[['func:and', ['variable:X', 'func:gt', 'value:13'], ['variable:Y', 'func:eq', 'variable:W']]]]

如果您已经写过generic_visit,那么在编写另一个将列表列表转换为字典的递归函数时,您不应该遇到任何困难。解决方案有点hacky。 (并且通过&#34;一点&#34;我的意思是它非常hacky。)我认为正确的解决方案是修改generic_visit

另外注意:字典不会保留其元素的顺序。使用OrderedDict确保function密钥首先出现。