Oh, und das funktioniert übrigens auch gar nicht innerhalb von Funktionen:
Code: Alles auswählen
In [321]: def frobnicate():
...: exec("Q42 = 23")
...: print(Q42)
...:
In [323]: frobnicate()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Input In [323], in <cell line: 1>()
----> 1 frobnicate()
Input In [322], in frobnicate()
1 def frobnicate():
2 exec("Q42 = 23")
----> 3 print(Q42)
NameError: name 'Q42' is not defined
Python ist sehr offen was die ”Innereien” angeht. So ziemlich jeder Mechanismus der Sprache liegt offen, kann benutzt und/oder verändert werden. Es gibt eine interaktive Shell, die startet wenn man kein Programm angibt das ausgeführt werden soll. Da kann man Code eingeben der Eingabe für Eingabe kompiliert und ausgeführt wird, in einem aktuellen Modulnamensraum. Um das umzusetzen braucht man Funktionen wie `compile()`, `exec()` und `eval()`. Wenn man eine eigene Python-Shell programmieren will, braucht man die. Es gibt ja mehrere Shells mit mehr Features, wie beispielsweise IPython. Wenn man einen Debugger oder eine IDE für Python programmiert sind das nützliche Funktionen. Wenn man so etwas wie das `timeit`-Modul aus der Standardbibliothek implementieren will, braucht man das. Wenn man den Python-Interpreter in ein Programm integriert, und dort die Möglichkeit anbieten will Python(-Schnippsel) auszuführen, braucht man das.
Um Zuweisungen der Art "<name> = <wert>" auszuwerten braucht man das nicht. Da missbraucht man ein viel mächtigeres und gefährlicheres Werkzeug um sich um ein paar Zeilen sauberen Code zu drücken, der nur das macht was man will, und nicht beliebigen Python-Code ausführt. Was ja auch bedeutet, das beliebige Ausnahmen auftreten können, und man die nicht sinnvoll behandeln kann.