Python-Kurs / JSON speichern, lesen und Daten ausdrücklich validieren
JSON, ausgeschrieben JavaScript Object Notation, ist ein Textformat für strukturierte Daten. Im Python-Modul json arbeiten load und dump mit Dateiobjekten, loads und dumps dagegen mit JSON-Text; das Format erhält nicht jeden möglichen Python-Typ unverändert.
JSON-Werte auf Python-Daten abbilden
| JSON | Übliche Python-Darstellung beim Lesen |
|---|---|
| object | dict |
| array | list |
| string | str |
| Ganzzahl / Zahl mit Dezimalteil | int / üblicherweise float |
| true / false / null | True / False / None |
JSON-Schlüssel und Zeichenketten verwenden doppelte Anführungszeichen. Ein Python-Wörterbuch mit einfachen Anführungszeichen ist nicht einfach derselbe Text in einem anderen Stil: json.loads erwartet JSON-Syntax. Beliebige Kommentare und ein abschließendes Komma sind ebenfalls keine erlaubten Ergänzungen.
Eine Python-Tupelstruktur kann nach Speichern und Lesen als Liste zurückkehren. Datumsobjekte und Decimal-Objekte werden vom Standardencoder nicht automatisch passend serialisiert. Legen Sie eine ausdrückliche Austauschdarstellung fest, wenn solche Typen wichtig sind. Die Python-Referenz zum JSON-Modul beschreibt die Konvertierung und Erweiterungsmöglichkeiten.
Einen Unicode-Datensatz speichern und zurücklesen
Verwenden Sie einen eigenen Übungsordner: Das Programm ersetzt expenses-demo.json bei jedem Start. Speichern Sie den folgenden vollständigen Code als json_demo.py in UTF-8 und führen Sie python json_demo.py mit dem Projektinterpreter aus. Unter macOS oder Ubuntu kann außerhalb einer aktivierten Umgebung python3 passen. Es werden keine Zusatzpakete und keine vorab erstellten Dateien benötigt.
import json
from pathlib import Path
data = {"currency": "KRW", "expenses": [{"name": "café", "amount": 8000}]}
path = Path("expenses-demo.json")
path.write_text(json.dumps(data, ensure_ascii=False, indent=2, allow_nan=False), encoding="utf-8")
loaded = json.loads(path.read_text(encoding="utf-8"))
amount = loaded["expenses"][0]["amount"]
if type(amount) is not int or amount < 0:
raise ValueError("invalid amount")
print(loaded["expenses"][0]["name"])
print(amount)
Erwartete Ausgabe:
café
8000
Der Name café enthält ein nicht rein ASCII-basiertes Zeichen und macht die Textdarstellung sichtbar. Die Einheit KRW und die Zahl 8000 bleiben unveränderte Beispieldaten. dumps erzeugt zunächst eine JSON-Zeichenkette. write_text speichert sie als UTF-8-Datei. Anschließend liest read_text den Text und loads wandelt ihn in Python-Daten zurück.
Die beiden Funktionenpaare unterscheiden sich an der Schnittstelle:
| Funktion | Richtung |
|---|---|
load(file) |
Aus lesbarem Dateiobjekt in Python-Daten |
loads(text) |
Aus JSON-Zeichenkette in Python-Daten |
dump(data, file) |
Python-Daten in ein schreibbares Dateiobjekt |
dumps(data) |
Python-Daten in eine JSON-Zeichenkette |
dumps erzeugt allein keine Datei. Wenn Sie direkt mit dump schreiben, öffnen Sie das Ziel ausdrücklich mit passender Kodierung und dem gewünschten Modus, wie in der Übung zu Textdateien. Wiederholtes Aneinanderhängen mehrerer vollständiger JSON-Dokumente ergibt nicht automatisch ein einzelnes gültiges JSON-Dokument.
Parsen von fachlicher Prüfung trennen
Ein syntaktisch lesbares Dokument kann trotzdem falsche Schlüssel, eine leere Liste oder einen unzulässigen Betrag enthalten. Das Beispiel nimmt eine bestimmte bekannte Struktur an: expenses ist eine Liste mit mindestens einem Eintrag, dessen Wörterbuch einen Betrag enthält. Es überprüft diese umgebenden Annahmen nicht vollständig. Ein allgemeiner Import muss die Schlüssel, Sammlungstypen und erforderlichen Einträge vor dem Zugriff prüfen.
Der Betrag wird hier ausdrücklich als gewöhnlicher eingebauter int mit nichtnegativem Wert verlangt. type(amount) is not int weist daher auch bool zurück, obwohl bool eine Unterklasse von int ist. Eine JSON-Zahl 8000.0 wird ebenfalls nicht als der geforderte Typ akzeptiert. Ob eine andere Anwendung Unterklassen oder Dezimalwerte zulassen möchte, ist eine gesonderte Eingaberegel.
allow_nan=False betrifft das Serialisieren: Es verhindert in dieser Schreiboperation die Ausgabe nichtstandardmäßiger Zahlenwerte wie NaN oder Infinity. Daraus folgt nicht, dass der anschließende Leser automatisch jede Form nichtstandardmäßiger Eingabe abweist. Python akzeptiert solche Konstanten beim Lesen standardmäßig; ebenso kann bei wiederholten Objektschlüsseln der spätere Wert den vorherigen ersetzen. Für strenge fremde Eingaben benötigen Sie eine bewusste Richtlinie, etwa passende parse_constant- und object_pairs_hook-Funktionen. Die Referenz zu Standardkonformität und Austausch erläutert diese Vorgaben und Abweichungen.
Zeichendarstellung, Fehler und veränderte Eingaben prüfen
ensure_ascii=False lässt den Namen im erzeugten Text lesbar stehen. Mit dem Standardwert True kann derselbe Name als Unicode-Escapesequenz erscheinen; beim Einlesen entsteht trotzdem wieder dieselbe Zeichenkette. Diese Option wählt nicht die Dateikodierung. encoding="utf-8" erledigt den Übergang zwischen Text und Bytes. indent=2 ändert die lesbare Einrückung, nicht die Bedeutung des Datensatzes.
- Ändern Sie in der Python-Zuweisung nur den Betrag 8000 zu
-1. Das JSON lässt sich schreiben und lesen, aber die fachliche Prüfung meldetValueError: invalid amount. - Ändern Sie ihn getrennt zu
True. In Python heißt der Wert mit großem TTrue; der JSON-Encoder schreibt daraustrue. Nach dem Lesen weist die Typprüfung den booleschen Betrag zurück. Schreiben Sie nicht den JSON-Bezeichnertrueals ungebundenen Python-Namen in das Skript. - Stellen Sie 8000 wieder her und vergleichen Sie die erzeugte Datei bei
ensure_ascii=TrueundFalse. Beide Varianten sollen wiedercaféund 8000 ergeben. - Wenn Sie eine nachträglich falsch bearbeitete Datei prüfen möchten, verwenden Sie einen getrennten Leser mit
json.loads(path.read_text(encoding="utf-8")). Ein vollständiger Neustart des ursprünglichen Programms würde Ihre manuelle Änderung zuerst überschreiben.
Ein abschließendes Komma oder falsche Anführungszeichen führen zu JSONDecodeError. Korrigieren Sie den Text anhand der Fehlerposition, statt zum Ausführen mit eval zu wechseln. Unterscheiden Sie diesen Syntaxfehler von beispielsweise KeyError bei einem fehlenden Schlüssel und IndexError bei einer leeren Liste. Stellen Sie zum Ende des Experiments die ursprünglichen Werte und Optionen wieder her und prüfen Sie beide Ausgabezeilen.




