Verhalten der Exec-Funktion in Python 2 und Python 3

Folgende Code gibt unterschiedliche Ausgabe in Python2 und in Python3 :

 from sys import version print(version) def execute(a, st): b = 42 exec("b = {}\nprint('b:', b)".format(st)) print(b) a = 1. execute(a, "1.E6*a") 

Python2 Drucke:

 2.7.2 (default, Jun 12 2011, 15:08:59) [MSC v.1500 32 bit (Intel)] ('b:', 1000000.0) 1000000.0 

Python3 Drucke:

 3.2.3 (default, Apr 11 2012, 07:15:24) [MSC v.1500 32 bit (Intel)] b: 1000000.0 42 

Warum bindet Python2 die Variable b innerhalb der execute Funktion an die Werte im String der exec Funktion, während Python3 das nicht macht? Wie kann ich das Verhalten von Python2 in Python3 ? Ich habe schon versucht, Wörterbücher für Globals und Einheimische zu Python3 , um Funktion in Python3 , aber nichts hat so weit gearbeitet.

— EDIT —

Nach dem Lesen von Martijns Antwort habe ich weiter analysiert mit Python3 . Im folgenden Beispiel gebe ich den locals() dictionay als d zu exec , aber d['b'] druckt etwas anderes als nur Druck b .

 from sys import version print(version) def execute(a, st): b = 42 d = locals() exec("b = {}\nprint('b:', b)".format(st), globals(), d) print(b) # This prints 42 print(d['b']) # This prints 1000000.0 print(id(d) == id(locals())) # This prints True a = 1. execute(a, "1.E6*a") 3.2.3 (default, Apr 11 2012, 07:15:24) [MSC v.1500 32 bit (Intel)] b: 1000000.0 42 1000000.0 True 

Der Vergleich der ids von d und locals() zeigt, dass sie das gleiche objekt sind Aber unter diesen Bedingungen sollte b das gleiche sein wie d['b'] . Was ist in meinem Beispiel falsch?

  • Die Anwendung der benutzerdefinierten Funktion während der Gruppierung gibt NaN zurück
  • Ich versuche, alle Buchstaben in einer txt-Datei zu zählen und dann in absteigender Reihenfolge anzuzeigen
  • Wie man zwei Python-Wörterbücher in einem einzigen Ausdruck zusammenführt?
  • Wie bekomme ich IPython Notebook, um Python 3 auszuführen?
  • Python shutil copy-Funktion fehlt letzten paar Zeilen
  • Warum verwandelt mein Code 18 anstelle von 10 und könntest du irgendwelche Lösungen anbieten?
  • Prozess vs. Thread in Bezug auf die Verwendung von Queue () / Deque () und Klasse Variable für Kommunikation und "Gift Pille"
  • Ersetzen von Zeilen der Ausgabe mit benutzerdefinierter Nachricht
  • 3 Solutions collect form web for “Verhalten der Exec-Funktion in Python 2 und Python 3”

    Es gibt einen großen Unterschied zwischen exec in Python 2 und exec() in Python 3. Sie behandeln exec als Funktion, aber es ist wirklich eine Aussage in Python 2.

    Wegen dieser Differenz können Sie keine lokalen Variablen im Funktionsumfang in Python 3 mit exec ändern, obwohl es in Python 2 möglich war. Nicht einmal zuvor deklarierte Variablen.

    locals() reflektieren nur lokale Variablen in einer Richtung. Das folgende arbeitete niemals in 2 oder 3:

     def foo(): a = 'spam' locals()['a'] = 'ham' print(a) # prints 'spam' 

    In Python 2 hatte der Compiler die Möglichkeit, die lokalen Bereichsoptimierungen LOAD_FAST (Umschalten von LOAD_FAST auf LOAD_NAME zum Beispiel, um Variablen sowohl im lokalen als auch im globalen Bereich nachzuschlagen). exec() eine Funktion ist, ist diese Option nicht mehr verfügbar und Funktionsbereiche sind nun immer optimiert.

    Darüber hinaus kopiert die exec Anweisung in Python 2 explizit alle Variablen, die in locals() zurück zu den Funktions-Einheimischen mit PyFrame_LocalsToFast , aber nur, wenn keine globals und locals- Parameter bereitgestellt wurden.

    Die richtige Arbeit ist, um einen neuen Namespace (ein Wörterbuch) für Ihren exec() Aufruf zu verwenden:

     def execute(a, st): namespace = {} exec("b = {}\nprint('b:', b)".format(st), namespace) print(namespace['b']) 

    Ich würde sagen, es ist ein Fehler von python3.

     def u(): exec("a=2") print(locals()['a']) u() 

    Druckt "2".

     def u(): exec("a=2") a=2 print(a) u() 

    Druckt "2".

    Aber

     def u(): exec("a=2") print(locals()['a']) a=2 u() 

    Scheitert mit

     Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in u KeyError: 'a' 

    — EDIT — Ein weiteres interessantes Verhalten:

     def u(): a=1 l=locals() exec("a=2") print(l) u() def u(): a=1 l=locals() exec("a=2") locals() print(l) u() 

    Ausgänge

     {'l': {...}, 'a': 2} {'l': {...}, 'a': 1} 

    Und auch

     def u(): l=locals() exec("a=2") print(l) print(locals()) u() def u(): l=locals() exec("a=2") print(l) print(locals()) a=1 u() 

    Ausgänge

     {'l': {...}, 'a': 2} {'l': {...}, 'a': 2} {'l': {...}, 'a': 2} {'l': {...}} 

    Anscheinend ist die Handlung von exec auf Einheimischen die folgenden:

    • Wenn eine Variable innerhalb von exec und diese Variable eine lokale Variable ist, dann exec modifiziert das interne Wörterbuch (das von den locals() ) zurückgegebene und gibt es nicht in den ursprünglichen Zustand zurück. Ein Aufruf von locals() aktualisiert das Wörterbuch (wie in Abschnitt 2 der Pythonendokumentation dokumentiert), und der Wert, der in exec ist, wird vergessen. Die Notwendigkeit des Aufrufs von locals() , um das Wörterbuch zu aktualisieren, ist kein Fehler von python3, weil es dokumentiert ist, aber es ist nicht intuitiv. Darüber hinaus ist die Tatsache, dass Änderungen von Einheimischen innerhalb von exec nicht ändern die Einheimischen der Funktion ist ein dokumentierter Unterschied mit python2 (die Dokumentation sagt "Pass ein explizites Einheimischen Wörterbuch, wenn Sie die Auswirkungen des Codes auf Einheimische nach der Funktion exec ( ) Gibt ") zurück, und ich bevorzuge das Verhalten von python2.
    • Wenn eine Variable innerhalb von exec und diese Variable vorher nicht existiert hat, dann exec modifiziert das interne Wörterbuch, wenn die Variable danach nicht gesetzt wird. Es scheint, dass es einen Bug in der Art, wie locals() aktualisiert das Wörterbuch; Dieser Bug gibt Zugriff auf den Wert, der in exec durch Aufruf von locals() nach exec .

    Ich fürchte, ich kann es nicht genau erklären, aber es kommt grundsätzlich aus der Tatsache, dass b in der Funktion lokal ist und exec() dem globalen B zuzuordnen scheint. Sie müssen deklarieren b, um global innerhalb der Funktion zu sein, und innerhalb der exec-Anweisung.

    Versuche dies:

     from sys import version print(version) def execute1(a, st): b = 42 exec("b = {}\nprint('b:', b)".format(st)) print(b) def execute2(a, st): global b b = 42 exec("global b; b = {}\nprint('b:', b)".format(st)) print(b) a = 1. execute1(a, "1.E6*a") print() execute2(a, "1.E6*a") print() b = 42 exec("b = {}\nprint('b:', b)".format('1.E6*a')) print(b) 

    Das gibt mir

     3.3.0 (default, Oct 5 2012, 11:34:49) [GCC 4.4.5] b: 1000000.0 42 b: 1000000.0 1000000.0 b: 1000000.0 1000000.0 

    Sie können sehen, dass außerhalb der Funktion die globale b automatisch abgeholt wird. Innerhalb der Funktion druckst du das lokale b.

    Beachten Sie, dass ich gedacht hätte, dass exec() immer das globale b zuerst verwendet, so dass es in execute2() nicht in der exec() Funktion deklarieren muss. Aber ich finde das geht nicht (was ich nicht genau erklären kann).

    Python ist die beste Programmiersprache der Welt.