2017-02-27 2 views
0

Ich arbeite an einem dummen Projekt in Python, das effektiv eine semi-REPL in einem Web-Browser implementiert, und ich bin fest, wie Code dynamisch während der Laufzeit sauber zu bewerten.Kompilieren Sie die Funktion von String im laufenden Betrieb in Python?

Grundsätzlich habe ich ein Web-Formular, wo der Benutzer eine Funktion eingibt, die dann auf dem Server ausgeführt werden soll.

Der erwartete Eintrag ist eine einzelne Funktion mit definierten Parametern. Der Funktionsname ist jedoch nicht angegeben.

Was ich will, ist eine Zeichenfolge zu erhalten, wie zum Beispiel:

def function_for_xxx(param_1, param_2, param_3): 
    <stuff goes here> 
    return interesting_value 

und irgendwie, dass Funktionsobjekt in ein normalen Python (z Objekt vom Typ <class 'function'>) zu konvertieren.

kann ich den Umfang der Aufgabe beschränken etwas:

  • Der Benutzer ausdrücklich ist vertrauenswürdig, so dass ich nicht über sanitization kümmern.
  • Es gibt einige Umgebungsfunktionen, die in die Funktion globals übergeben werden sollten, aber ich kann sie explizit angeben.
  • Das Erzwingen der Schnur, die eine einzelne bloße Funktion ist, ist wirklich wünschenswert.

Gerade jetzt, ich habe ein wenig mit den compile() und exec() Anrufen experimentiert, aber sie scheinen den exec() ed Code in den aktuellen lokalen Bereich einzufügen, die nicht ideal ist. Ich würde wirklich mögen, dass die Exec ohne solche Nebenwirkungen gemacht wird, und einfach ein Modul oder die bloße Funktion zurückgibt.

+0

Warum können Sie es nicht als .py-Datei speichern und ausführen? – MotKohn

+0

@MotKohn - Das bewegt nur das Problem herum. Dann müsste ich Module im laufenden Betrieb laden. Und es ist viel weniger elegant. Und ich habe eine * Menge * dieser Funktionen, die alle unabhängig voneinander geändert werden können (mehrere hundert bis einige tausend). –

Antwort

0

Ok, ich habe einen Workaround gefunden, der irgendwie hackisch ist, aber tut was ich will.

Grundsätzlich können wir die Tatsache ausnutzen, dass wir den Ausführungsumfang auf exec() Aufrufe angeben können, indem Sie den Parameter globals angeben.

func_container = compile(func"\n", "<dynamic_functions_xxx>", "exec") 

scope = { 
    <objects made available to the dynamic function> 
} 
exec(func_container, scope) 

Objekte in dem func String definiert sind nun in dem scope Variable, ohne Nebenwirkungen auf dem lokalen Namespace.

Allgemeine Kommentare gelten hier. Wenn Sie den Compile/Exec-Prozess notieren können, ist dies wahrscheinlich eine gute Idee (Kompilieren ist langsam!).

Verwandte Themen