Aufwärmen · Aufgabe 1 von 7
Aufwärmen aus der vorigen Lektion: Was gibt das aus?
port = 8080
print(t"{port}".values)// A5.2 · ca. 30 Min. · Vertiefung
Nach dieser Lektion lesen Sie eine TOML-Datei oder einen TOML-String mit tomllib, sagen den Python-Typ jedes Werts vorher und prüfen das Ergebnis mit Fehlermeldungen, die den fehlerhaften Schlüssel nennen.
Danach können Sie
Aufwärmen · Aufgabe 1 von 7
port = 8080
print(t"{port}".values)Vorhersagen · Aufgabe 2 von 7
import tomllib
data = tomllib.loads("port = 8080\ndebug = true\n")
print(data, type(data["port"]).__name__)Üben · Aufgabe 3 von 7
import tomllib
with open("config.toml", ____) as f:
config = tomllib.load(f)
print(config["name"])Üben · Aufgabe 4 von 7
import tomllib
doc = """
released = 2026-09-29
[[server]]
name = "a"
[[server]]
name = "b"
"""
data = tomllib.loads(doc)
print(type(data["released"]).__name__, type(data["server"]).__name__, data["server"][1])Üben · Aufgabe 5 von 7
Denksport · Aufgabe 6 von 7
import tomllib
config = tomllib.loads("workers = true\n")
workers = config["workers"]
if isinstance(workers, int):
print("workers:", workers + 1)
else:
print("not a number")Anwenden · Aufgabe 7 von 7
Prüfen Sie Ihr Ergebnis anhand dieser Liste
Lesen Sie das ausgearbeitete Beispiel und lösen Sie dann die Übungen. Ihr Code läuft in Ihrem Browser oder auf Ihrem Computer und wird nie hochgeladen.
Ausgearbeitetes Beispiel
config.toml beschreibt einen kleinen Dienst: einen Titel, ein Veröffentlichungsdatum, eine Tabelle [database] und zwei Einträge [[servers]]. main.py öffnet die Datei im Binärmodus, lädt sie und liest Werte verschiedener Typen. Am Ende parst es ein fehlerhaftes Dokument mit demselben Schlüssel zweimal und gibt Meldung und Zeile aus, die TOMLDecodeError mitbringt. Beide Dateien stehen im Editor: Ändern Sie config.toml und starten Sie erneut.
main.py
import tomllib
with open("config.toml", "rb") as f: # binary mode: tomllib decodes UTF-8 itself
config = tomllib.load(f)
print(config["title"])
print(config["database"])
print(type(config["released"]).__name__, config["released"].year)
for server in config["servers"]:
print(f"{server['name']}: {server['ip']}")
try:
tomllib.loads("port = 80\nport = 81\n")
except tomllib.TOMLDecodeError as err:
print("error:", err.msg, "at line", err.lineno)
config.toml
# Settings for the report service
title = "Report service"
released = 2026-09-29
[database]
host = "db.local"
port = 5432
enabled = true
[[servers]]
name = "alpha"
ip = "10.0.0.1"
[[servers]]
name = "beta"
ip = "10.0.0.2"
Ausführen mit
python main.pyAusgabe
Report service
{'host': 'db.local', 'port': 5432, 'enabled': True}
date 2026
alpha: 10.0.0.1
beta: 10.0.0.2
error: Cannot overwrite a value at line 2Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser Python herunter (bis zu 6.5 MB) und speichert es im Cache. Ihr Code bleibt auf Ihrem Gerät.
Übung 1 von 2
Korrigieren Sie beide Funktionen in main.py. read_port(path) liefert server.port aus einer TOML-Datei. read_price(path) liefert den Preis price der obersten Ebene als exaktes Decimal, sodass price = 0.1 Decimal("0.1") ergibt, nicht den float 0.1. Der Starter öffnet die Dateien im Textmodus, und das lehnt tomllib ab.
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser Python herunter (bis zu 6.5 MB) und speichert es im Cache. Ihr Code bleibt auf Ihrem Gerät.
tomllib.load will eine Binärdatei: open(path, "rb"). Im Binärmodus gibt es kein encoding-Argument.
Verschachtelte Tabellen sind verschachtelte dicts: config["server"]["port"].
tomllib.load(f, parse_float=Decimal) ruft Decimal mit dem Text jeder TOML-Kommazahl auf.
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
import tomllib
from decimal import Decimal
def read_port(path: str) -> int:
"""Return server.port from the TOML file at path."""
with open(path, "rb") as f:
config = tomllib.load(f)
return config["server"]["port"]
def read_price(path: str) -> Decimal:
"""Return price from the TOML file at path, as an exact Decimal."""
with open(path, "rb") as f:
config = tomllib.load(f, parse_float=Decimal)
return config["price"]
Installieren Sie Python 3.14 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.py
import tomllib
from decimal import Decimal
def read_port(path: str) -> int:
"""Return server.port from the TOML file at path."""
with open(path, encoding="utf-8") as f:
config = tomllib.load(f)
return config["server"]["port"]
def read_price(path: str) -> Decimal:
"""Return price from the TOML file at path, as an exact Decimal."""
with open(path, encoding="utf-8") as f:
config = tomllib.load(f)
return config["price"]
test_main.py
from decimal import Decimal
from main import read_port, read_price
def write(name, text):
with open(name, "w", encoding="utf-8") as f:
f.write(text)
return name
def test_port():
"""server.port wird aus der Datei gelesen"""
path = write("app.toml", '[server]\nhost = "0.0.0.0"\nport = 8080\n')
got = read_port(path)
assert got == 8080, f"read_port lieferte {got!r}, erwartet 8080"
def test_other_file():
"""Eine andere Datei liefert ihren eigenen Port"""
path = write("other.toml", "[server]\nport = 9000\n")
got = read_port(path)
assert got == 9000, f"read_port lieferte {got!r}, erwartet 9000"
def test_price_exact():
"""price = 0.1 kommt als Decimal('0.1') zurück"""
path = write("shop.toml", "price = 0.1\n")
got = read_price(path)
assert isinstance(got, Decimal) and got == Decimal("0.1"), f"read_price lieferte {got!r}, erwartet Decimal('0.1')"
Unter macOS und Linux tippen Sie python3, wo in diesen Befehlen python steht, wie in der ersten Lektion.
Programm ausführen:
python main.pyPrüfungen ausführen (learnrun.py muss im selben Ordner liegen):
python learnrun.py testlearnrun.py herunterladenÜbung 2 von 2
Vervollständigen Sie load_settings(text). Parsen Sie das TOML und lösen Sie ValueError mit dem Schlüssel in der Meldung aus, wenn: ein Schlüssel nicht in ALLOWED steht; name fehlt oder kein nicht leerer str ist; port kein int von 1 bis 65535 ist (bool zählt nicht); debug vorhanden, aber kein bool ist. Geben Sie {"name": ..., "port": ..., "debug": ...} zurück, debug ohne Angabe False.
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser Python herunter (bis zu 6.5 MB) und speichert es im Cache. Ihr Code bleibt auf Ihrem Gerät.
set(config) - ALLOWED liefert die unbekannten Schlüssel. Ist die Menge nicht leer, lösen Sie aus.
config.get("port") liefert bei fehlendem Schlüssel None, und isinstance(None, int) ist False: Eine Prüfung deckt Fehlen und falschen Typ ab.
Schließen Sie bool ausdrücklich aus: not isinstance(port, int) or isinstance(port, bool) or not 1 <= port <= 65535.
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
import tomllib
ALLOWED = {"name", "port", "debug"}
def load_settings(text: str) -> dict[str, object]:
"""Parse TOML settings and check them; raise ValueError on any problem."""
config = tomllib.loads(text) # TOMLDecodeError is a ValueError too
unknown = set(config) - ALLOWED
if unknown:
raise ValueError(f"unknown key: {sorted(unknown)[0]}")
name = config.get("name")
if not isinstance(name, str) or not name:
raise ValueError("name must be a non-empty string")
port = config.get("port")
if not isinstance(port, int) or isinstance(port, bool) or not 1 <= port <= 65535:
raise ValueError("port must be an integer from 1 to 65535")
debug = config.get("debug", False)
if not isinstance(debug, bool):
raise ValueError("debug must be true or false")
return {"name": name, "port": port, "debug": debug}
Installieren Sie Python 3.14 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.py
import tomllib
ALLOWED = {"name", "port", "debug"}
def load_settings(text: str) -> dict[str, object]:
"""Parse TOML settings and check them; raise ValueError on any problem."""
config = tomllib.loads(text)
# Check: no key outside ALLOWED; name a non-empty str; port an int
# (not a bool) from 1 to 65535; debug a bool, False when missing.
return config
test_main.py
from main import load_settings
def error_of(text):
try:
load_settings(text)
except ValueError as err:
return str(err)
return None
def test_valid():
"""Eine vollständige, gültige Konfiguration wird zurückgegeben"""
got = load_settings('name = "api"\nport = 8080\ndebug = true\n')
assert got == {"name": "api", "port": 8080, "debug": True}, f"load_settings lieferte {got!r}"
def test_debug_default():
"""debug ist ohne Angabe False"""
got = load_settings('name = "api"\nport = 8080\n')
assert got == {"name": "api", "port": 8080, "debug": False}, f"load_settings lieferte {got!r}"
def test_missing_name():
"""Ein fehlender name löst ValueError aus, der den Schlüssel nennt"""
got = error_of("port = 8080\n")
assert got is not None and "name" in got, f"erwartet ValueError mit name in der Meldung, erhalten {got!r}"
def test_port_bool():
"""port = true wird abgelehnt, obwohl True ein int ist"""
got = error_of('name = "api"\nport = true\n')
assert got is not None and "port" in got, f"erwartet ValueError mit port in der Meldung, erhalten {got!r}"
def test_port_text_and_range():
"""port = "80" und port = 70000 werden abgelehnt"""
got = error_of('name = "api"\nport = "80"\n'), error_of('name = "api"\nport = 70000\n')
assert None not in got, f"erwartet zwei ValueErrors, erhalten {got!r}"
def test_unknown_key():
"""Ein vertippter Schlüssel wie prot wird gemeldet"""
got = error_of('name = "api"\nport = 8080\nprot = 1\n')
assert got is not None and "prot" in got, f"erwartet ValueError mit prot in der Meldung, erhalten {got!r}"
def test_bad_toml():
"""Ungültiges TOML löst ebenfalls ValueError aus"""
got = error_of("name = api\n")
assert got is not None, "ungültiges TOML hat keinen ValueError ausgelöst"
Unter macOS und Linux tippen Sie python3, wo in diesen Befehlen python steht, wie in der ersten Lektion.
Programm ausführen:
python main.pyPrüfungen ausführen (learnrun.py muss im selben Ordner liegen):
python learnrun.py testlearnrun.py herunterladenimport tomllib
with open("app.toml", "w", encoding="utf-8") as f:
f.write('name = "demo"\n')
with open("app.toml", encoding="utf-8") as f:
config = tomllib.load(f)
Was Python ausgibt
TypeError: File must be opened in binary mode, e.g. use `open('foo.toml', 'rb')`Warum, und die Lösung
tomllib.load liest Bytes und dekodiert sie selbst als UTF-8, denn TOML-Dateien sind immer UTF-8. Öffnen Sie die Datei mit open(path, "rb") und lassen Sie encoding= weg. Haben Sie den Text schon als str, rufen Sie stattdessen tomllib.loads(text) auf.
import tomllib
data = b'name = "demo"'
config = tomllib.loads(data)
Was Python ausgibt
TypeError: Expected str object, not 'bytes'Warum, und die Lösung
loads nimmt einen str. Bytes, etwa aus dem Netz oder einer ZIP-Datei, dekodieren Sie zuerst, tomllib.loads(data.decode("utf-8")), oder Sie verpacken sie für load: tomllib.load(io.BytesIO(data)).
import tomllib
config = tomllib.loads("name = unquoted")
Was Python ausgibt
tomllib.TOMLDecodeError: Invalid value (at line 1, column 8)Warum, und die Lösung
In TOML braucht jeder String Anführungszeichen: name = "unquoted". Nur Zahlen, true, false, Datumsangaben, Arrays und Tabellen stehen ohne. Zeile und Spalte in der Meldung zeigen auf das erste Zeichen, das der Parser nicht lesen konnte.
Python im Browser: Pyodide 314.0.7, MPL-2.0. Lizenz und Quellcode
5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.
Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.