2016-10-04 101 views
1

我正在使用Python ast模塊來解析表達式,如X >= 13 and Y == W。我需要的是在下面發現了一個預購字典來改造這個表達式:Python AST to dictionary structure

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

的Python AST給我驗證語法和值差分變量的好處。下面的代碼做一個基本的解析,但注意到輸出不預先訂購,我不完全知道如何PROCEDE:

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)))) 
+0

您能舉一個預期結果的例子嗎? –

+0

@LaurentLAPORTE:預期的結果是帖子頂部的字典。 – PepperoniPizza

回答

1

考慮這些小的變化 - 我已經添加' S和逗號:

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你不應該在寫另一遞歸函數,將列出的這份清單轉換成字典面對任何困難。該解決方案有點怪異。 (通過「一點」我的意思是它真的很黑。)我想應該是修改generic_visit

另外還有一點:詞典不保留它們的元素順序。使用OrderedDict確保function鍵先行。