Python und JSON sind ein natürliches Paar. Ob Sie eine REST-API mit FastAPI oder Django entwickeln, Datenpipelines verarbeiten oder einfach eine Konfigurationsdatei lesen — Sie arbeiten ständig mit JSON. Die gute Nachricht: Die Standardbibliothek von Python hat alles, was Sie brauchen, im json-Modul. Kein pip install erforderlich.

Die vier Funktionen, die Sie wirklich verwenden

Das json-Modul bietet vier Funktionen für die tägliche Arbeit:

  • json.loads(str) — parst einen JSON-String in ein Python-Objekt
  • json.dumps(obj) — konvertiert ein Python-Objekt in einen JSON-String
  • json.load(file) — parst JSON direkt aus einem Datei-Objekt
  • json.dump(obj, file) — schreibt ein Python-Objekt als JSON in eine Datei

Das s in loads / dumps steht für String. Die Funktionen ohne das s arbeiten mit Dateiobjekten. Leicht zu merken, wenn man die Regel kennt.

json.loads() — Einen JSON-String parsen

python
import json

json_string = '{"name": "Alice", "age": 30, "active": true, "score": 98.5}'

user = json.loads(json_string)

print(user["name"])    # Alice
print(user["age"])     # 30
print(user["active"])  # True
print(type(user))      # <class 'dict'>

Beachten Sie das Typ-Mapping: JSON true wird zu Python True, JSON false wird zu Python False, JSON null wird zu Python None. JSON-Objekte werden zu Python dict, JSON-Arrays zu Python list.

json.dumps() — In einen JSON-String serialisieren

python
import json

user = {
    "name": "Bob",
    "age": 25,
    "roles": ["admin", "editor"],
    "active": True,
    "extra": None
}

# Kompakt (gut für die Netzwerkübertragung)
compact = json.dumps(user)
print(compact)
# {"name": "Bob", "age": 25, "roles": ["admin", "editor"], "active": true, "extra": null}

# Hübsch formatiert (gut für Logs und menschliche Inspektion)
pretty = json.dumps(user, indent=2)
print(pretty)
# {
#   "name": "Bob",
#   "age": 25,
#   "roles": [
#     "admin",
#     "editor"
#   ],
#   "active": true,
#   "extra": null
# }

Beachten Sie das umgekehrte Typ-Mapping: Python True → JSON true, Python None → JSON null. Python erledigt das automatisch.

JSON aus einer Datei lesen

Dies ist wahrscheinlich der häufigste Anwendungsfall — das Lesen einer Konfigurations- oder Datendatei beim Start:

python
import json

# In einem Schritt lesen und parsen
with open("config.json", "r", encoding="utf-8") as f:
    config = json.load(f)

print(config["database"]["host"])  # localhost
print(config["database"]["port"])  # 5432

Geben Sie beim Öffnen von JSON-Dateien immer encoding="utf-8" an. JSON ist per RFC 8259 als UTF-8 spezifiziert, und das Weglassen kann unter Windows zu Problemen führen, wo die Standardkodierung manchmal cp1252 ist.

JSON in eine Datei schreiben

python
import json

results = {
    "timestamp": "2024-01-15T09:30:00Z",
    "total": 1523,
    "processed": 1521,
    "failed": 2,
    "errors": [
        {"id": 42, "reason": "missing field"},
        {"id": 99, "reason": "invalid format"}
    ]
}

with open("results.json", "w", encoding="utf-8") as f:
    json.dump(results, f, indent=2)

print("Results saved to results.json")

Fehler richtig behandeln

json.loads() wirft json.JSONDecodeError (eine Unterklasse von ValueError), wenn die Eingabe kein gültiges JSON ist. Behandeln Sie dies immer, wenn Sie Daten parsen, die Sie nicht kontrollieren:

python
import json

def safe_parse(json_str):
    try:
        return json.loads(json_str)
    except json.JSONDecodeError as e:
        print(f"Invalid JSON at line {e.lineno}, column {e.colno}: {e.msg}")
        return None

data = safe_parse('{"name": "Alice"}')   # funktioniert problemlos
bad  = safe_parse('not json at all')     # gibt Fehler aus, gibt None zurück
also_bad = safe_parse('{"key": }')       # gibt Fehler mit Positionsinfo aus

JSONDecodeError gibt die genaue Zeile und Spalte an, wo das Parsen fehlgeschlagen ist, was beim Debuggen großer JSON-Dateien nützlich ist.

Nützliche dumps()-Optionen

python
import json

data = {
    "z_key": 1,
    "a_key": 2,
    "price": 9.999999999
}

# Schlüssel alphabetisch sortieren (ideal für reproduzierbare Ausgabe / Diffs)
print(json.dumps(data, sort_keys=True, indent=2))
# {
#   "a_key": 2,
#   "price": 9.999999999,
#   "z_key": 1
# }

# Sicherstellen, dass Nicht-ASCII-Zeichen erhalten bleiben (Standard: als \uXXXX escaped)
data2 = {"city": "Münich", "greeting": "こんにちは"}
print(json.dumps(data2, ensure_ascii=False))
# {"city": "Münich", "greeting": "こんにちは"}

# Mit ensure_ascii=True (Standard):
print(json.dumps(data2))
# {"city": "M\u00fcnich", "greeting": "\u3053\u3093\u306b\u3061\u306f"}

ensure_ascii=False füge ich immer hinzu, wenn ich JSON-Dateien mit Nicht-ASCII-Text schreibe. Die escapte Version ist technisch gültiges JSON, aber in einem Texteditor viel schwieriger zu lesen.

Benutzerdefinierte Objekte serialisieren

Standardmäßig kann json.dumps() keine Instanzen benutzerdefinierter Klassen oder datetime-Objekte serialisieren. Sie haben zwei Möglichkeiten: Erstellen einer Unterklasse von json.JSONEncoder oder zuerst in ein dict konvertieren:

python
import json
from datetime import datetime, date

# Option 1: benutzerdefinierte Encoder-Klasse
class AppEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, (datetime, date)):
            return obj.isoformat()
        return super().default(obj)

data = {"name": "Alice", "created_at": datetime(2024, 1, 15, 9, 30)}
print(json.dumps(data, cls=AppEncoder, indent=2))
# {
#   "name": "Alice",
#   "created_at": "2024-01-15T09:30:00"
# }

# Option 2: default=-Parameter (einfacher für einmalige Konvertierungen)
print(json.dumps(data, default=str, indent=2))  # konvertiert alles Unbekannte zu str

Ein praktisches Muster: Konfigurationsdatei laden

Hier ist ein Praxismuster, das ich in fast jedem Python-Projekt verwende — ein Konfigurations-Loader, der eine JSON-Konfigurationsdatei mit sinnvollen Standardwerten liest:

python
import json
import os
from pathlib import Path

DEFAULTS = {
    "database": {"host": "localhost", "port": 5432},
    "debug": False,
    "log_level": "INFO"
}

def load_config(path="config.json"):
    config = DEFAULTS.copy()

    config_path = Path(path)
    if config_path.exists():
        with open(config_path, "r", encoding="utf-8") as f:
            try:
                user_config = json.load(f)
                # Tiefes Zusammenführen: Benutzereinstellungen überschreiben Standardwerte
                for key, value in user_config.items():
                    if isinstance(value, dict) and key in config:
                        config[key].update(value)
                    else:
                        config[key] = value
            except json.JSONDecodeError as e:
                print(f"Warning: config.json is invalid ({e.msg}), using defaults")

    return config

config = load_config()
print(config["database"]["host"])  # localhost (oder überschriebener Wert)

Fazit

Pythons json-Modul deckt alles ab, was Sie ohne externe Abhängigkeiten benötigen. Die wichtigsten Regeln: loads()/dumps() für Strings, load()/dump() für Dateien, immer JSONDecodeError beim Parsen externer Daten behandeln, und ensure_ascii=False hinzufügen, wenn Ihre Daten Nicht-Latein-Zeichen enthalten. Beim Debuggen von JSON-Daten können der JSON-Formatierer und der JSON-Validator viel Zeit sparen.