Was ist der Unterschied zwischen eval, exec und kompilieren in Python?

Ich habe die dynamische Auswertung von Python-Code untersucht und über die Funktionen eval() und compile() und die exec Anweisung gekommen.

Kann jemand bitte den Unterschied zwischen eval und exec erklären und wie die verschiedenen Modi von compile() passen?

3 Solutions collect form web for “Was ist der Unterschied zwischen eval, exec und kompilieren in Python?”

Die kurze Antwort, oder TL; DR

Grundsätzlich wird eval verwendet, um einen einzigen dynamisch erzeugten Python-Ausdruck zu evalieren, und exec wird verwendet, um den dynamisch erzeugten Python-Code nur für seine Nebenwirkungen auszuführen.

eval und exec haben diese beiden Unterschiede:

  1. eval akzeptiert nur einen einzigen Ausdruck , exec kann einen Codeblock mit Python-Anweisungen nehmen: Loops, try: except: :, class und function / method def initions und so weiter.

    Ein Ausdruck in Python ist was auch immer du als Wert in einer Variablenzuordnung haben kannst:

     a_variable = (anything that you can put into these parentheses is an expression) 
  2. eval gibt den Wert des angegebenen Ausdrucks zurück, während exec den Rückgabewert aus seinem Code ignoriert und immer None zurückgibt (in Python 2 ist es eine Anweisung und kann nicht als Ausdruck verwendet werden, also gibt es wirklich nichts zurück).

In den Versionen 1.0 – 2.7 war exec eine Aussage, denn CPython musste eine andere Art von Codeobjekt für Funktionen erstellen, die für seine Nebenwirkungen in der Funktion ausgeführt wurden.

In Python 3 ist exec eine Funktion; Es erzeugt immer die gleiche Art von Code-Objekt, unabhängig davon, ob es in einer Funktion oder im Modulumfang aufgerufen wird.


Also grundsätzlich:

 >>> a = 5 >>> eval('37 + a') # it is an expression 42 >>> exec('37 + a') # it is an expression statement; value is ignored (None is returned) >>> exec('a = 47') # modify a global variable as a side effect >>> a 47 >>> eval('a = 47') # you cannot evaluate a statement Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1 a = 47 ^ SyntaxError: invalid syntax 

Die compile im 'exec' Modus kompiliert eine beliebige Anzahl von Anweisungen in einen Bytecode, der implizit immer None zurückgibt, während im 'eval' Modus ein einzelner Ausdruck in einen Bytecode kompiliert wird, der den Wert dieses Ausdrucks zurückgibt .

 >>> eval(compile('42', '<string>', 'exec')) # code return None >>> eval(compile('42', '<string>', 'eval')) # code returns 42 42 >>> exec(compile('42', '<string>', 'eval')) # code returns 42, >>> # but ignored by exec 

Im 'eval' -Modus (und damit mit der eval Funktion, wenn ein String weitergegeben wird), erhebt das compile eine Ausnahme, wenn der Quellcode Aussagen oder irgendetwas anderes über einen einzigen Ausdruck enthält:

 >>> compile('for i in range(3): print(i)', '<string>', 'eval') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1 for i in range(3): print(i) ^ SyntaxError: invalid syntax 

Eigentlich gilt die Anweisung "eval nur einen einzigen Ausdruck" gilt nur, wenn ein String (der Python- Quellcode enthält ) an eval . Dann ist es intern kompiliert zu Bytecode mit compile(source, '<string>', 'eval') Hier kommt der Unterschied wirklich aus.

Wenn ein Codeobjekt (das Python- Bytecode enthält) an exec oder eval , verhalten sie sich identisch , mit Ausnahme der Tatsache, dass exec den Rückgabewert ignoriert und immer noch immer zurückkehrt. So ist es möglich, eval auszuführen, um etwas auszuführen, das Aussagen hat, wenn man es einfach in Bytecode compile anstatt es als String zu übergeben:

 >>> eval(compile('if 1: print("Hello")', '<string>', 'exec')) Hello >>> 

Funktioniert ohne Probleme, obwohl der kompilierte Code Aussagen enthält. Es gibt immer noch None , denn das ist der Rückgabewert des None , das von compile .

Im 'eval' -Modus (und damit mit der eval Funktion, wenn ein String weitergegeben wird), erhebt das compile eine Ausnahme, wenn der Quellcode Aussagen oder irgendetwas anderes über einen einzigen Ausdruck enthält:

 >>> compile('for i in range(3): print(i)', '<string>'. 'eval') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1 for i in range(3): print(i) ^ SyntaxError: invalid syntax 

Die längere Antwort, aka die blutigen Details

exec und eval

Die exec Funktion (die eine Anweisung in Python 2 war ) wird für die Ausführung einer dynamisch erstellten Anweisung oder des Programms verwendet:

 >>> program = 'for i in range(3):\n print("Python is cool")' >>> exec(program) Python is cool Python is cool Python is cool >>> 

Die eval Funktion tut dasselbe für einen einzelnen Ausdruck und gibt den Wert des Ausdrucks zurück:

 >>> a = 2 >>> my_calculation = '42 * a' >>> result = eval(my_calculation) >>> result 84 

exec und eval akzeptieren das Programm / den Ausdruck, der entweder als str , unicode oder bytes Objekt mit Quellcode oder als Codeobjekt mit Python-Bytecode ausgeführt werden soll.

Wenn ein str / unicode / bytes mit Quellcode an exec , verhält es sich äquivalent zu:

 exec(compile(source, '<string>', 'exec')) 

Und eval verhält sich ähnlich wie folgt:

 eval(compile(source, '<string>', 'eval')) 

Da alle Ausdrücke als Anweisungen in Python verwendet werden können (diese heißen die Expr Knoten in der Python- abstrakten Grammatik , das Gegenteil ist nicht wahr), kannst du immer exec wenn du den Rückgabewert nicht Expr . Das heißt, du kannst entweder eval('my_func(42)') oder exec('my_func(42)') , wobei der Unterschied ist, dass eval den von my_func Wert my_func , und exec verwirft es:

 >>> def my_func(arg): ... print("Called with %d" % arg) ... return arg * 2 ... >>> exec('my_func(42)') Called with 42 >>> eval('my_func(42)') Called with 42 84 >>> 

Von den 2, nur exec akzeptiert Quellcode, der Aussagen enthält, wie def , for , while , import oder class , die Zuweisungsanweisung (aka a = 42 ) oder ganze Programme:

 >>> exec('for i in range(3): print(i)') 0 1 2 >>> eval('for i in range(3): print(i)') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1 for i in range(3): print(i) ^ SyntaxError: invalid syntax 

Sowohl exec als auch eval akzeptieren 2 zusätzliche Positionsargumente – globals und locals – das sind die globalen und lokalen Variablen, die der Code sieht. Diese Voreinstellung für die globals() und die locals() innerhalb des Bereichs, der exec oder eval , kann aber jedes Wörterbuch für globals und jede mapping für locals (einschließlich dict of course) verwendet werden. Diese können nicht nur verwendet werden, um die Variablen, die der Code sieht, zu beschränken / zu modifizieren, sondern werden oft auch für die Erfassung der Variablen verwendet, die der ausgeführte Code erstellt:

 >>> g = {} >>> l = {} >>> exec('global a; a, b = 123, 42', g, l) >>> g['a'] 123 >>> l {'b': 42} 

(Wenn du den Wert von ganzen g anzeigt, wäre es viel länger, weil exec und eval das eingebaute Modul als __builtins__ zu den globals automatisch hinzufügen, wenn es fehlt).

In Python 2 ist die offizielle Syntax für die exec Anweisung eigentlich exec code in globals, locals , wie in

 >>> exec 'global a; a, b = 123, 42' in g, l 

Allerdings wurde die alternative Syntax exec(code, globals, locals) immer auch akzeptiert (siehe unten).

compile

Die compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1) eingebaut kann verwendet werden, um wiederholte Aufrufe des gleichen Codes mit exec oder eval zu beschleunigen, indem die Quelle zuvor in ein eval kompiliert wird . Der mode Parameter steuert die Art des Code-Fragments, die die compile akzeptiert und die Art des Bytecodes, den sie erzeugt. Die Entscheidungen sind 'eval' , 'exec' und 'single' :

  • 'eval' -Modus erwartet einen einzigen Ausdruck und wird Bytecode erzeugen, der beim Ausführen den Wert dieses Ausdrucks zurückgibt :

     >>> dis.dis(compile('a + b', '<string>', 'eval')) 1 0 LOAD_NAME 0 (a) 3 LOAD_NAME 1 (b) 6 BINARY_ADD 7 RETURN_VALUE 
  • 'exec' akzeptiert jede Art von Python-Konstrukte von einzelnen Ausdrücken zu ganzen Code-Modellen und führt sie aus, als wären sie Modul-Top-Level-Anweisungen. Das Codeobjekt gibt None :

     >>> dis.dis(compile('a + b', '<string>', 'exec')) 1 0 LOAD_NAME 0 (a) 3 LOAD_NAME 1 (b) 6 BINARY_ADD 7 POP_TOP <- discard result 8 LOAD_CONST 0 (None) <- load None on stack 11 RETURN_VALUE <- return top of stack 
  • 'single' ist eine limitierte Form von 'exec' die einen Quellcode mit einer einzelnen Anweisung (oder mehrere Anweisungen getrennt durch ; ) akzeptiert ; wenn die letzte Anweisung eine Ausdrucksanweisung ist, druckt der resultierende Bytecode auch den Wert des Wertes dieses Ausdrucks Zum Standardausgang (!) .

    Eine ifelifelse – Kette, eine Schleife mit else , und try mit dem except , else und finally Blöcke gilt als eine einzige Aussage.

    Ein Quellfragment mit 2 Top-Level-Anweisungen ist ein Fehler für die 'single' , außer in Python 2 gibt es einen Bug , der manchmal mehrere toplevel Anweisungen in den Code erlaubt; Nur das erste ist kompiliert; Der Rest wird ignoriert:

    In Python 2.7.8:

     >>> exec(compile('a = 5\na = 6', '<string>', 'single')) >>> a 5 

    Und in Python 3.4.2:

     >>> exec(compile('a = 5\na = 6', '<string>', 'single')) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1 a = 5 ^ SyntaxError: multiple statements found while compiling a single statement 

    Dies ist sehr nützlich für die Herstellung von interaktiven Python-Muscheln. Allerdings wird der Wert des Ausdrucks nicht zurückgegeben , auch wenn Sie den resultierenden Code eval .

Die größte Unterscheidung von exec und eval stammt tatsächlich aus der compile und ihren Modi.


Zusätzlich zum Kompilieren von Quellcode zu Bytecode unterstützt compile die Erstellung von abstrakten Syntaxbäumen (Parse-Bäume des Python-Codes) in code . Und Quellcode in abstrakte Syntax-Bäume (die ast.parse ist in Python geschrieben und ruft nur compile(source, filename, mode, PyCF_ONLY_AST) ); Diese werden zum Beispiel zum Ändern des Quellcodes on the fly und auch zur dynamischen Codeerstellung verwendet, da es oft einfacher ist, den Code als Baum der Knoten anstelle von Textzeilen in komplexen Fällen zu behandeln.


Während eval nur erlaubt, einen String zu bewerten, der einen einzelnen Ausdruck enthält, kannst du eine ganze Anweisung oder sogar ein ganzes Modul, das in Bytecode compile , auswerten; Das heißt, mit Python 2 ist print eine Aussage und kann nicht direkt eval geführt werden:

 >>> eval('for i in range(3): print("Python is cool")') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1 for i in range(3): print("Python is cool") ^ SyntaxError: invalid syntax 

compile es mit 'exec' Modus in ein code Objekt und du kannst es eval ; Die eval Funktion gibt None .

 >>> code = compile('for i in range(3): print("Python is cool")', 'foo.py', 'exec') >>> eval(code) Python is cool Python is cool Python is cool 

Wenn man in CPython 3 in eval und exec Quellcode schaut, ist das sehr offensichtlich; Sie rufen beide PyEval_EvalCode mit den gleichen Argumenten an, der einzige Unterschied ist, dass exec explizit None zurückgibt .

Syntaxunterschiede von exec zwischen Python 2 und Python 3

Einer der Hauptunterschiede in Python 2 ist, dass exec eine Aussage ist und eval eine eingebaute Funktion ist (beide sind eingebaute Funktionen in Python 3). Es ist eine bekannte Tatsache, dass die offizielle Syntax von exec in Python 2 exec code [in globals[, locals]] .

Anders als die Mehrheit der Python-2-zu-3- Porting- Guides scheinen vorzuschlagen , kann die exec Anweisung in CPython 2 auch mit der Syntax verwendet werden, die genau wie die exec Funktionsaufruf in Python 3 aussieht . Der Grund dafür ist, dass Python 0.9.9 die exec(code, globals, locals) eingebaute Funktion! Und diese eingebaute Funktion wurde ersetzt durch exec Anweisung irgendwo vor Python 1.0 Release .

Da es wünschenswert war, die Kompatibilität mit Python 0.9.9 nicht zu brechen, fügte Guido van Rossum 1993 einen Kompatibilitätshack hinzu : Wenn der code ein Tupel der Länge 2 oder 3 war und globals und locals nicht in die exec Aussage übergeben wurden, Der code würde so interpretiert werden, als ob das 2. und 3. Element des Tupels die globals und locals waren. Der Kompatibilitäts-Hack wurde auch in der Python 1.4-Dokumentation nicht erwähnt (die früheste verfügbare Version online) ; Und so war es nicht vielen Schriftstellern der portierenden Führer und Werkzeuge bekannt, bis es im November 2012 nochmals dokumentiert wurde:

Der erste Ausdruck kann auch ein Tupel der Länge 2 oder 3 sein. In diesem Fall müssen die optionalen Teile weggelassen werden. Das Formular exec(expr, globals) ist äquivalent zu exec expr in globals , während das Formular exec(expr, globals, locals) äquivalent zu exec expr in globals, locals . Die Tupelform von exec bietet Kompatibilität mit Python 3, wobei exec eine Funktion und nicht eine Anweisung ist.

Ja, in CPython 2.7, dass es handlungsweise als eine Vorwärtskompatibilitätsoption bezeichnet wird (warum verwirren die Menschen darüber, dass es eine Rückwärtskompatibilitätsoption überhaupt gibt), als es tatsächlich für eine Rückwärtskompatibilität für zwei Jahrzehnte gewesen war .

Während also exec eine Anweisung in Python 1 und Python 2 ist und eine eingebaute Funktion in Python 3 und Python 0.9.9,

 >>> exec("print(a)", globals(), {'a': 42}) 42 

Hat identisches Verhalten in möglicherweise jede weit verbreitete Python-Version überhaupt gehabt; Und arbeitet in Jython 2.5.2, PyPy 2.3.1 (Python 2.7.6) und IronPython 2.6.1 auch (kudos zu ihnen nach dem undokumentierten Verhalten von CPython genau).

Was Sie in Pythons 1.0 – 2.7 nicht mit seinem Kompatibilitätshack tun können, ist, den Rückgabewert von exec in eine Variable zu speichern:

 Python 2.7.11+ (default, Apr 17 2016, 14:00:29) [GCC 5.3.1 20160413] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> a = exec('print(42)') File "<stdin>", line 1 a = exec('print(42)') ^ SyntaxError: invalid syntax 

(Was in Python 3 auch nicht sinnvoll wäre, da exec immer None zurückgibt) oder einen Verweis auf exec :

 >>> call_later(exec, 'print(42)', delay=1000) File "<stdin>", line 1 call_later(exec, 'print(42)', delay=1000) ^ SyntaxError: invalid syntax 

Welches ein Muster, das jemand tatsächlich benutzt hätte, wenn auch unwahrscheinlich;

Oder benutze es in einem Listenverständnis:

 >>> [exec(i) for i in ['print(42)', 'print(foo)'] File "<stdin>", line 1 [exec(i) for i in ['print(42)', 'print(foo)'] ^ SyntaxError: invalid syntax 

Was ist ein Missbrauch von Listenverständnissen (verwenden Sie eine for Schleife statt!).

  1. exec ist kein Ausdruck: eine Anweisung in Python 2.x und eine Funktion in Python 3.x. Es kompiliert und gibt sofort eine Anweisung oder einen Satz von Anweisung aus, die in einem String enthalten ist. Beispiel:

     exec('print(5)') # prints 5. # exec 'print 5' if you use Python 2.x, nor the exec neither the print is a function there exec('print(5)\nprint(6)') # prints 5{newline}6. exec('if True: print(6)') # prints 6. exec('5') # does nothing and returns nothing. 
  2. eval ist eine eingebaute Funktion ( keine Aussage), die einen Ausdruck auswertet und den Wert zurückgibt, den der Ausdruck erzeugt. Beispiel:

     x = eval('5') # x <- 5 x = eval('%d + 6' % x) # x <- 11 x = eval('abs(%d)' % -100) # x <- 100 x = eval('x = 5') # INVALID; assignment is not an expression. x = eval('if 1: x = 4') # INVALID; if is a statement, not an expression. 
  3. compile ist eine niedrigere Version von exec und eval . Es führt weder Ihre Aussagen noch Ausdrücke aus, sondern gibt ein Codeobjekt zurück, das es tun kann. Die Modi sind wie folgt:

    1. compile(string, '', 'eval') gibt das compile(string, '', 'eval') zurück, das ausgeführt worden wäre, wenn du eval(string) gemacht hast. Beachten Sie, dass Sie in diesem Modus keine Anweisungen verwenden können. Es ist nur ein (einzelner) Ausdruck gültig.
    2. compile(string, '', 'exec') gibt das compile(string, '', 'exec') zurück, das ausgeführt wurde, wenn du exec(string) gemacht hast. Hier können Sie beliebig viele Aussagen verwenden.
    3. compile(string, '', 'single') ist wie der exec Modus, aber es wird alles außer der ersten Anweisung ignorieren. Beachten Sie, dass eine if / else Anweisung mit ihren Ergebnissen als eine einzige Anweisung betrachtet wird.

Exec ist für die Aussage und gibt nichts zurück. Eval ist für den Ausdruck und gibt den Wert des Ausdrucks zurück.

Ausdruck bedeutet "etwas", während Aussage bedeutet "etwas tun".

  • Dynamic / Runtime-Methodenerstellung (Codegenerierung) in Python
  • Python 2.7 / exec / was ist falsch
  • Wie kann ich die Funktion im aktuellen Bereich dynamisch ausführen und als Eigenschaft der Aufruffunktion hinzufügen?
  • Python: die druckausgabe in einer exec-ausgabe erhalten
  • Unicode zu PHP exec
  • Die Lösung, um Argumente an Python-Prozess mit Runtime.exec zu senden
  • Python-Objekt Persistenz über Re-Execs
  • Wie man parallele Kinderprozesse auf einem Multiprozessorsystem auflöst?
  • Ein Python-Skript aus PHP ausführen
  • Funktion intern mit exec (astring) mit einer Variablendefinition innerhalb von astring kann die Variable nicht in python 3 zurückgeben
  • Python: Wie man Argumente an den __code__ einer Funktion übergibt?
  • Python ist die beste Programmiersprache der Welt.