2012-11-12 4 views
5

Ich muss eine Eingabezeichenfolge (aus einer Datenbank) als eine Funktion kompilieren und ausführen. Dies ist die Methode, die ich zur Zeit verwenden:Wie kompiliere ich Text als Funktion mit AST?

sagen, ich habe bereits diese Funktion definiert:

def foo(): 
    print "Yo foo! I am a function!" 

Und die Zeichenfolge ich aus der Datenbank eingelesen sagt sollte ich diese Funktion aufrufen:

string_from_db = "foo()" 

ich bilde dann eine Funktion (dessen Namen ich steuern kann), die die Funktion zurückgibt ich aus der Datenbank eingelesen:

my_func_string = "def doTheFunc():\n\t return " + string_from_db 

Jetzt kompilieren ich die Zeichenfolge, und legen Sie es auf einen Funktionsnamen ich später für die Verarbeitung verwenden:

exec my_func_string 
processor = doTheFunc 

ich es später nennen kann processor(), indem Sie die ausruft: Yo foo! I am a function!

Meine Frage: Above dieses Stück Code gibt es einen Kommentar (durch einen lange verlorenen Entwickler links): „potentiellen Ersatz“

############################################################### 
    # The following method for getting a function out of the text # 
    # in the database could potentially be replaced by using  # 
    # Python's ast module to obtain an abstract syntax tree and # 
    # put it inside of a function node       # 
    ############################################################### 

Ich mag würde mehr darüber wissen Ich habe mir AST angesehen, aber ich bin sehr verwirrt darüber, wie es mir helfen kann, das zu tun, was ich bereits mit dem obigen Code mache.

  1. Wie kann ich dasselbe mit AST erreichen? Oder wo kann AST mir dabei helfen?
  2. Ist die Implementierung mit AST besser, und warum?
+5

Ihr seid im Reich der dunklen Magie. –

+1

Wenn Sie die Zeichenfolgen als sicher kennen, gibt es keinen Grund, 'ast' über' exec() 'zu verwenden. Der Python-Interpreter implementiert bereits das Parsen von Python-Quellcode in Funktionsobjekte, warum replizieren? – millimoose

+0

@millimoose Ich bin mit der 'exec'-Implementierung gegangen, da ich weiß, dass meine Strings sicher sind. Diese Frage hat mich jedoch zu besseren Verwendungen für 'ast' erleuchtet. Vielen Dank! – dinkelk

Antwort

5

AST ist eine viel sicherere Wahl, wenn nicht vertrauenswürdigen Code Auswertung, dass bösartige Anweisungen enthalten könnte, eval oder exec jeden Ausdruck ausführen kann, während AST auf der anderen Seite, können Sie den Ausdruck selbst analysieren und zu validieren, oder ausführen ein begrenzter Ausdruck mit ast.literal_eval, eine Art Sandbox, die nur Strings, Listen, Zahlen und ein paar andere Dinge erlaubt. Dies ist nur ein einfaches Beispiel:

import ast 
a = ast.literal_eval("[1,2,3,4]") //evaluate an expression safely. 

Ein weiteres Beispiel, das einen String in einen AST parst:

import ast 
source = '2 + 2' 
node = ast.parse(source, mode='eval') 
ast.dump(node) 

Diese Drucke:

Expression(body=BinOp(left=Num(n=2), op=Add(), right=Num(n=2))) 

Es ist ein sehr gutes Tutorial here und auch die documentation

+0

Tolles Tutorial! Wie würde ich "einen Ausdruck für mich selbst bestätigen"? Wie kann ich feststellen, ob der Code fehlerhaft ist oder nicht meinen Anforderungen entspricht? Vorausgesetzt, ich werde kleine Funktionen kompilieren müssen; Ich kann mich nicht auf einfache Strings, Listen usw. beschränken. – dinkelk

+0

@babydanks können Sie herausfinden, ob es irgendwelche Funktionen nennt, die es nicht tun sollte, wie 'open' vielleicht. – iabdalkader

+0

Ah! Auf welcher Ebene ist das am einfachsten? Sobald Sie einen Ast-Funktionsknoten haben? (z. B. was wäre der einfachste Weg nach "offen" zu suchen?) – dinkelk