Die Python-Funktion eval(expression) parst einen String als Python-Ausdruck und wertet ihn aus. Das macht sie extrem mächtig — und extrem gefährlich. Mit eval() lassen sich Strings in beliebigen Python-Code verwandeln, was sie zur klassischen Schwachstelle für Code-Injection macht. Für sichere Auswertung von Literalen ist ast.literal_eval() fast immer die richtige Alternative.
Einleitung
eval() parst einen String als Expression (also einen Ausdruck, keine Statement-Liste) und wertet ihn im aktuellen Scope aus. Damit lassen sich:
- Mathematische Formeln aus String-Eingaben rechnen.
- Konfiguration in Python-Syntax laden.
- Dynamisch Attribute oder Funktionen aufrufen.
Das Sicherheitsproblem: Solange die Eingabe komplett unter eigener Kontrolle ist, ist eval() ok. Sobald sie aus User-Input, Netz, Datei oder DB kommt, ist sie lebensgefährlich:
eval("__import__('os').system('rm -rf /')")
Wer nur Literale auswerten will — also Listen, Dicts, Tupel, Strings, Zahlen, Booleans — nutzt ast.literal_eval(), das nur diese erlaubt.
Syntax
eval(expression, globals=None, locals=None)expression Ein String (oder ein per compile() vorbereitetes Code-Objekt) mit einem Python-Ausdruck.
globals (Optional) Dict mit globalen Variablen. Default: aktuelle Globals.
locals (Optional) Dict mit lokalen Variablen. Default: aktuelle Locals.
Rückgabewert
Das Ergebnis des ausgewerteten Ausdrucks. Bei Syntax-Fehlern: SyntaxError, bei Laufzeit-Fehlern: die jeweilige Exception.
Beispiele
Einfacher Ausdruck
eval() hat Zugriff auf den aktuellen Scope — Variablen werden korrekt aufgelöst:
x = 10
print(eval("x * 2 + 5"))25Mit eingeschränkten Globals
Mit explizitem globals lässt sich der Zugriff einschränken — ein leeres Dict deaktiviert alle Builtins außer __builtins__:
# Eigene globale Symbole bereitstellen, alles andere blockieren
safe_globals = {"__builtins__": {}, "pi": 3.14159}
result = eval("pi * 2", safe_globals)
print(result)6.28318Sicher: ast.literal_eval
Für Literale ist ast.literal_eval() der idiomatische, sichere Ersatz — er parst nur Datenstrukturen, keine Funktionsaufrufe:
from ast import literal_eval
print(literal_eval("[1, 2, 3]"))
print(literal_eval("{'a': 1, 'b': 2}"))
print(literal_eval("(3.14, 'pi', True)"))
# Schlägt fehl bei Ausdrücken oder Funktionsaufrufen:
try:
literal_eval("__import__('os').system('ls')")
except (ValueError, SyntaxError) as e:
print("Blockiert:", type(e).__name__)[1, 2, 3]
{'a': 1, 'b': 2}
(3.14, 'pi', True)
Blockiert: ValueErrorPraktische Beispiele
Mini-Taschenrechner (mit Vorsicht)
Wer eine Formel-Eingabe baut, sollte mindestens den Ausdruck per compile() validieren — eval() direkt mit User-Input ist nie eine gute Idee:
import math
ALLOWED_NAMES = {k: getattr(math, k) for k in dir(math) if not k.startswith("_")}
ALLOWED_NAMES["abs"] = abs
ALLOWED_NAMES["round"] = round
def calc(expr: str):
code = compile(expr, "<input>", "eval")
for name in code.co_names:
if name not in ALLOWED_NAMES:
raise NameError(f"'{name}' nicht erlaubt")
return eval(code, {"__builtins__": {}}, ALLOWED_NAMES)
print(calc("sqrt(2) * pi"))4.442882938158366Konfig aus Python-Datei laden — besser nicht eval()
Statt eine Python-Datei zu evaluieren, lieber JSON oder TOML nutzen — sicher, portabel, sprachunabhängig:
# SCHLECHT:
config = eval(open("config.py").read())
# GUT:
import json
with open("config.json") as f:
config = json.load(f)
# ODER, falls Python-Literal-Syntax gewünscht:
from ast import literal_eval
with open("config.py") as f:
config = literal_eval(f.read())Praktische Hinweise
- NIEMALS
eval()auf User-Input — Code-Injection ist Standard-Beute. ast.literal_eval()ist der sichere Default für Datenstruktur-Parsing.globalsundlocalseinschränken hilft kaum — Angreifer haben elaborierte Wege, an__builtins__heranzukommen.- Performance:
eval()hat Parsing-Overhead — für mehrfache Aufrufe das Code-Objekt mitcompile()cachen. - Verwandte Funktionen:
exec()(Statements ausführen),compile()(vorab kompilieren),ast.literal_eval()(sicher).