Abschnitt 12 · Lektion 5
JSON
Der Aufräumer für den Download-Ordner soll eine neue Endung kennen, und dafür muss das Programm geändert werden. Seine Einstellungen stehen nämlich im Code, also welcher Ordner und welche Endung wohin. Nach genau solchen Änderungen läuft dann plötzlich nichts mehr.
Einstellungen gehören in eine eigene Datei, die das Programm beim Start liest. Eine CSV passt dafür schlecht, weil Einstellungen keine Tabelle sind. Darin steckt ein Dictionary mit Endungen, vielleicht eine Liste, ein Ja oder Nein. Für so etwas gibt es JSON (JavaScript Object Notation). Wie der Name sagt, kommt das aus JavaScript. Heute speichern aber Programme in fast jeder Sprache ihre Einstellungen und Daten darin, und die meisten Dienste im Netz antworten in JSON.
JSON ist Text
import json
einstellungen = {
"ordner": "Downloads",
"probelauf": True,
"zuletzt": None,
"endungen": {".jpg": "Bilder", ".pdf": "Dokumente"},
"hinweis": "Läuft freitags",
}
text = json.dumps(einstellungen)
print(text)
print(type(text)) json.dumps (dump string) macht aus einem Dictionary einen Text in JSON, und der sieht fast genauso
aus wie das Dictionary. Die Unterschiede sind klein, aber wichtig. True und False heißen true
und false, None heißt null, und Text steht immer in doppelten Anführungszeichen, auch bei den
Schlüsseln.
JSON kennt Text, Zahlen, true, false, null, Listen in eckigen Klammern und Objekte in
geschweiften. Objekte heißen sie in JSON, und sie sehen aus wie Dictionaries. Mehr gibt es nicht.
Das ä in „Läuft“ steht als \u00e4 da, seine Nummer in Unicode. Das ist gültiges JSON, und beim
Einlesen kommt wieder ein ä heraus. Lesen kann es so nur kein Mensch. Weiter unten steht, wie man
das abstellt.
Einlesen
{
"ordner": "Downloads",
"probelauf": true,
"endungen": {
".jpg": "Bilder",
".png": "Bilder",
".pdf": "Dokumente"
}
} import json
with open("einstellungen.json", encoding="utf-8") as datei:
einstellungen = json.load(datei)
print(einstellungen)
print(einstellungen["probelauf"], type(einstellungen["probelauf"]))
print(einstellungen["endungen"][".pdf"]) json.load liest JSON aus einer geöffneten Datei und baut daraus Python. Aus dem Objekt wird ein
Dictionary, aus true wird True, und das innere Objekt mit den Endungen ist ein Dictionary im
Dictionary. Abgefragt wird es wie jedes andere, mit zwei Schlüsseln hintereinander.
Anders als bei einer CSV ist hier nicht alles Text. true kommt als True heraus und eine Zahl als
Zahl. Rechnen geht also ohne Umwandlung.
Ändern und zurückschreiben
{
"ordner": "Downloads",
"probelauf": true,
"endungen": {
".jpg": "Bilder",
".png": "Bilder",
".pdf": "Dokumente"
}
} import json
with open("einstellungen.json", encoding="utf-8") as datei:
einstellungen = json.load(datei)
einstellungen["probelauf"] = False
einstellungen["endungen"][".zip"] = "Archive"
einstellungen["hinweis"] = "Läuft freitags"
with open("einstellungen.json", "w", encoding="utf-8") as datei:
json.dump(einstellungen, datei, indent=2, ensure_ascii=False)
with open("einstellungen.json", encoding="utf-8") as datei:
print(datei.read()) Bei Einstellungen sind es immer drei Schritte. Alles einlesen, im Dictionary ändern, alles zurück in
dieselbe Datei. json.dump schreibt in eine geöffnete Datei, und mit zwei Angaben wird das Ergebnis
lesbar.
indent=2 rückt jede Ebene um zwei Leerzeichen ein, statt alles in eine lange Zeile zu schreiben.
ensure_ascii=False lässt Umlaute als Umlaute in der Datei, statt \u00e4 daraus zu machen. Danach
ist die Datei etwas, das man mit jedem Editor öffnen und verstehen kann, und das will man bei
Einstellungen ja auch.
Damit stehen allerdings wieder echte Umlaute in der Datei, und die Kodierung aus Lektion 11.2 ist
wieder wichtig. Ohne encoding="utf-8" schriebe Python unter Windows das € in der alten
Windows-Kodierung, und ein Programm, das UTF-8 erwartet, scheitert daran. Deshalb steht sie beim
Lesen und beim Schreiben dabei.
Die Reihenfolge ist dabei nicht egal. Durch das "w" beim Öffnen wird die Datei sofort geleert.
Wenn du sie zum Schreiben öffnest, bevor du sie gelesen hast, liest du danach eine leere Datei, und
die Einstellungen sind weg. Also erst lesen, dann schreiben, jedes in seinem eigenen with.
Der neue Eintrag „hinweis“ steht übrigens am Ende. Ein Dictionary behält die Reihenfolge, in der
seine Schlüssel hineinkamen, und json.dump schreibt sie genau so.
Was JSON nicht kennt
import json
from decimal import Decimal
summe = Decimal("1204.00")
print(json.dumps({"monat": "09.2026", "wohnen": str(summe)}))
print(json.dumps({"monat": "09.2026", "wohnen": summe})) Die erste Zeile klappt. Die zweite endet mit
TypeError: Object of type Decimal is not JSON serializable, und seit Python 3.14 steht in der
Zeile darunter, wo es passiert ist, when serializing dict item 'wohnen', also beim Eintrag
„wohnen“.
Ein Decimal aus Lektion 10.5 gehört nicht zu dem, was JSON kennt, und Python rät nicht, was daraus
werden soll. Bei einem Datum ist es genauso.
Beide macht man vorher selbst zu Text. Ein Decimal mit str(), das genau die Ziffern schreibt,
die darin stehen, und ein Datum mit strftime. Wird die Datei später wieder eingelesen, macht
Decimal("1204.00") aus "1204.00" wieder einen genauen Betrag. Über eine Kommazahl ginge das
nicht, die ist nicht genau.
Von Hand bearbeitet
{
"ordner": "Downloads",
"probelauf": false,
} import json
with open("einstellungen.json", encoding="utf-8") as datei:
einstellungen = json.load(datei) Eine Datei mit Einstellungen wird früher oder später von Hand geändert. Und dabei passiert der häufigste Fehler in JSON überhaupt, ein Komma hinter dem letzten Eintrag. In Python ist das erlaubt, in JSON nicht.
Das Programm endet mit
json.decoder.JSONDecodeError: Illegal trailing comma before end of object: line 3 column 21 (char 47).
Auf Deutsch heißt das, ein Komma zu viel vor dem Ende des Objekts, in Zeile 3, Spalte 21. Python
3.12 meldet an dieser Stelle noch „Expecting property name enclosed in double quotes“ und zeigt auf
die Zeile danach. Das ist ungefähr so hilfreich, wie es klingt.
Was die Aufgabe will
Das Haushaltsbuch bekommt eine neue Fassung, und dafür braucht es drei Änderungen an seinen Einstellungen. Gebraucht wird ein kleines Programm, das sie einliest, ändert und wieder zurückschreibt, ohne etwas anderes darin anzufassen.
Zum Mitnehmen
Eine JSON-Datei liest sich fast wie Python-Code, nur stehen true, false und null dort klein, und Texte haben nur doppelte Anführungszeichen. Herein kommt sie mit json.load(datei), zurück geht sie mit json.dump(daten, datei, indent=2, ensure_ascii=False), eingerückt und mit echten Umlauten. Decimal oder date kennt JSON nicht, die werden vorher zu Text.
Jetzt du
Basis Konto, kostenlosZu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.
Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.
In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.
Was in dieser Lektion steckt
-
Artikel mit 5 Beispielen zum Ausprobieren
Steht hier, ohne Konto lesbar.
-
Aufgabe, dein Code läuft auf einem Server
Öffnet sich mit dem Basis Konto.