Python Language
Dynamische Code-Ausführung mit "exec" und "eval"
Suche…
Syntax
- eval (Ausdruck [, Globals = Keine [, Einheimische = Keine]]
- exec (Objekt)
- exec (Objekt, Globals)
- exec (Objekt, Globals, Einheimische)
Parameter
Streit | Einzelheiten |
---|---|
expression | Der Ausdruck Code als String oder ein code - Objekt |
object | Die Anweisung Code als String oder ein code - Objekt |
globals | Das für globale Variablen zu verwendende Wörterbuch. Wenn für Einheimische keine Angabe gemacht wird, wird dies auch für Einheimische verwendet. Wenn nicht angegeben, werden die globals() des aufrufenden Bereichs verwendet. |
locals | Ein Mapping- Objekt, das für lokale Variablen verwendet wird. Wenn nicht angegeben, wird stattdessen die für globals verwendet. Wenn beide weggelassen werden, werden die globals() und locals() des aufrufenden Bereichs für globals bzw. locals verwendet. |
Bemerkungen
In exec
, wenn globals
ist locals
(dh sie auf das gleiche Objekt verweisen), wird der Code ausgeführt , als ob es auf der Modulebene ist. Wenn globals
und locals
unterschiedliche Objekte sind, wird der Code so ausgeführt, als wäre er in einem Klassenkörper .
Wenn das globals
Objekt übergeben wird, der globals
__builtins__
Schlüssel jedoch nicht angegeben ist, werden die __builtins__
Funktionen und Namen von Python automatisch zum globalen Bereich hinzugefügt. Um die Verfügbarkeit von Funktionen wie print
oder isinstance
im ausgeführten Bereich zu unterdrücken, lassen Sie globals
den Schlüssel __builtins__
auf den Wert None
. Dies ist jedoch keine Sicherheitsfunktion.
Die Python 2-spezifische Syntax sollte nicht verwendet werden. Die Python 3-Syntax funktioniert in Python 2. Daher sind die folgenden Formulare veraltet: <s>
-
exec object
-
exec object in globals
-
exec object in globals, locals
Aussagen mit exec auswerten
>>> code = """for i in range(5):\n print('Hello world!')"""
>>> exec(code)
Hello world!
Hello world!
Hello world!
Hello world!
Hello world!
Auswerten eines Ausdrucks mit eval
>>> expression = '5 + 3 * a'
>>> a = 5
>>> result = eval(expression)
>>> result
20
Einen Ausdruck vorkompilieren, um ihn mehrmals auszuwerten
compile
eingebaute Funktion compile
kann verwendet werden, um einen Ausdruck in ein Codeobjekt vorzukompilieren. Dieses Codeobjekt kann dann an eval übergeben werden. Dies beschleunigt die wiederholte Ausführung des ausgewerteten Codes. Der dritte zu compile
Parameter muss die Zeichenfolge 'eval'
.
>>> code = compile('a * b + c', '<string>', 'eval')
>>> code
<code object <module> at 0x7f0e51a58830, file "<string>", line 1>
>>> a, b, c = 1, 2, 3
>>> eval(code)
5
Auswerten eines Ausdrucks mit eval mit benutzerdefinierten Globals
>>> variables = {'a': 6, 'b': 7}
>>> eval('a * b', globals=variables)
42
Als Plus kann sich der Code hier nicht versehentlich auf die außerhalb definierten Namen beziehen:
>>> eval('variables')
{'a': 6, 'b': 7}
>>> eval('variables', globals=variables)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'variables' is not defined
Bei Verwendung von defaultdict
können zum Beispiel undefinierte Variablen auf Null gesetzt werden:
>>> from collections import defaultdict
>>> variables = defaultdict(int, {'a': 42})
>>> eval('a * c', globals=variables) # note that 'c' is not explicitly defined
0
Auswertung eines Strings, der ein Python-Literal enthält, mit ast.literal_eval
Wenn Sie über eine Zeichenfolge verfügen, die Python-Literale enthält, z. B. Zeichenfolgen, Floats usw., können Sie ast.literal_eval
, um den Wert anstelle von eval
auszuwerten. Dies hat die zusätzliche Eigenschaft, nur bestimmte Syntax zuzulassen.
>>> import ast
>>> code = """(1, 2, {'foo': 'bar'})"""
>>> object = ast.literal_eval(code)
>>> object
(1, 2, {'foo': 'bar'})
>>> type(object)
<class 'tuple'>
Dies ist jedoch nicht sicher für die Ausführung von Code, der von nicht vertrauenswürdigen Benutzern bereitgestellt wird, und es ist trivial, einen Interpreter mit sorgfältig ausgearbeiteten Eingaben zum Absturz zu bringen
>>> import ast
>>> ast.literal_eval('()' * 1000000)
[5] 21358 segmentation fault (core dumped) python3
Hier ist die Eingabe eine Zeichenfolge von ()
eine Million Mal wiederholt wird, was zu einem Absturz des CPython-Parsers führt. CPython-Entwickler betrachten Fehler im Parser nicht als Sicherheitsprobleme.
Ausführen von Code, der von nicht vertrauenswürdigem Benutzer mit exec, eval oder ast.literal_eval bereitgestellt wird
Es ist nicht möglich, eval
oder exec
zu verwenden, um Code von nicht vertrauenswürdigen Benutzern sicher auszuführen. Selbst ast.literal_eval
neigt im Parser zum Absturz. Es kann manchmal vor böswilliger Code-Ausführung geschützt werden, schließt aber nicht aus, dass der Parser oder der Tokenizer vollständig abstürzt.
Um Code von einem nicht vertrauenswürdigen Benutzer auszuwerten, müssen Sie sich an ein Drittanbieter-Modul wenden oder vielleicht Ihren eigenen Parser und Ihre eigene virtuelle Maschine in Python schreiben.