2016-10-04 1 views
1

Ich verwende das Python ast Modul, um Ausdrücke wie X >= 13 and Y == W zu analysieren. Was ich brauche, ist dieser Ausdruck in einem Pre-Order-Wörterbuch unten gefunden zu transformieren:Python AST zu Dictionary Struktur

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

Python AST gibt mir den Vorteil der Syntax Validierung und von Werten differenzier Variablen. Der folgende Code hat eine grundlegende Parsing aber feststellen, der Ausgang ist nicht vorbestellen und ich bin mir nicht ganz sicher, wie voll vorzugehen:

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) 

Ausgang

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

Können Sie ein Beispiel für das erwartete Ergebnis geben? –

+0

@LaurentLAPORTE: Das erwartete Ergebnis ist das Wörterbuch oben auf dem Beitrag. – PepperoniPizza

Antwort

1

Betrachten Sie diese kleinen Änderungen - I habe hinzugefügt ' s und Komma:

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) 

An diesem Punkt tree ist eine gültige Liste:

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

Wenn Sie generic_visit geschrieben haben, sollten Sie keine Schwierigkeiten haben, in eine andere rekursive Funktion schreiben, die diese Liste der Listen in ein Wörterbuch konvertieren. Die Lösung ist ein bisschen hacky. (Und mit "ein bisschen", ich meine, es ist wirklich hacky.) Die richtige Lösung wäre zu ändern generic_visit, nehme ich an.

Und auf einer separaten Notiz: Wörterbücher bewahren nicht die Reihenfolge ihrer Elemente. Verwenden Sie OrderedDict, um sicherzustellen, function Schlüssel geht zuerst.