Werkboek — Hoofdstuk 7: Foutafhandeling (exceptions)
Let op: alle programmacode schrijf je in het Engels (zoals in het boek). De uitleg en opdrachten zijn in het Nederlands.
Doel van dit hoofdstuk
- Exceptions begrijpen en gericht afvangen met
try/except(specifiek boven generiek). - Succes‑logica in
elseplaatsen en altijd‑opruimen infinallyof viawithdoen. - Fouten zelf signaleren met
raiseen, waar passend, her‑gooien met logging (re‑raise) of exception chaining gebruiken. - Eenvoudig en defensief valideren; kies tussen herstelbare en terminale fouten.
logginggebruiken i.p.v.printvoor foutmeldingen.
Richtlijnen
- Houd je
try‑blok zo klein mogelijk (alleen de riskante regels). - Vang specifieke excepties; vermijd
except:en te bredeexcept Exception:zonder goede reden. - Scheid kernlogica (pure functies) van I/O waar mogelijk; laat helpers waarden teruggeven in plaats van printen.
Oefening 1 — safe_int helper (geen prints in kernfunctie)
Schrijf een functie safe_int(text: str, default: int | None = None) -> int | None die probeert int(text) te retourneren. Als dat niet lukt, geef default terug (kan None zijn).
- Schrijf in
__main__3 korte voorbeelden.
Oefening 2 — read_float met komma‑ondersteuning
Schrijf read_float(prompt: str) -> float die blijft vragen tot er een geldige float is ingevoerd. Sta komma als decimaalteken toe (vervang door punt).
- Gebruik
try/except ValueError. - Geen exception uit de functie laten lekken; de functie moet altijd met een
floateindigen.
Oefening 3 — Calculator met ^ (macht) en nette foutmeldingen
Schrijf calc(a: float, op: str, b: float) -> float die + - * / ^ ondersteunt.
raise ZeroDivisionErrorbij deling door nul.raise ValueErrorbij onbekende operatoren. Schrijf een__main__dat invoer vraagt en fouten netjes afvangt met specifieke messages.
Oefening 4 — else en finally in context
Schrijf een klein script dat een bestand probeert te openen, de lengte van de inhoud print in else, en in finally altijd "Done" print. Gebruik daarna de with‑variant (contextmanager) die hetzelfde doet zonder expliciet finally.
Oefening 5 — Eigen exceptie: ConfigError
Maak een class ConfigError(Exception) en een functie load_config(path: str) -> dict[str, str] die een tekstbestand leest met regels key=value.
- Lege regels en regels die met
#beginnen negeren. - Gooi
ConfigErrorals het bestand ontbreekt, een regel ongeldig is, of een sleutel dubbel voorkomt. - Gebruik specifieke excepties en evt. exception chaining (
from e) voor context.
Oefening 6 — Re‑raise met logging
Schrijf een functie risky_div(a: float, b: float) -> float die kan falen met ZeroDivisionError.
- In de aanroepende code: vang elke exception, log met
logging.exception("..."), en her‑gooi de exception. - Laat zien dat de traceback gelogd wordt en de fout verderop nog zichtbaar is.
Oefening 7 — Exception chaining (context behouden)
Schrijf parse_price(text: str) -> int die int(text) probeert. Bij ValueError gooi je ValueError(f"invalid price '{text}'") from e.
- Demonstreer in
__main__de resulterende traceback (context zichtbaar).
Oefening 8 — Recoverable vs. terminal Schrijf een mini‑programma dat bedragen leest tot een lege regel. Ongeldige invoer:
- Toon een vriendelijke melding en ga door (recoverable).
- Als er 3 fouten op rij zijn, print een laatste fout en
sys.exit(1)(terminal pad). Tel de fouten met een teller.
Oefening 9 — Te brede excepties aanscherpen Gegeven het (foutieve) patroon:
try:
amount = float(input("Amount: "))
print(100 / amount)
except Exception:
print("Something went wrong")
- Herschrijf dit met specifieke excepties, correcte volgorde, en een kleine
try‑scope. - Licht toe met 1–2 comments waarom dit beter is.
Oefening 10 — Logging i.p.v. print
Configureer basislogging met niveau INFO. Vang een FileNotFoundError en log een nette boodschap met log.error(...). Laat ook een voorbeeld zien van logging.exception(...) binnen een except‑blok.
Uitdaging (optioneel) — Robuuste key=value loader met types
Breid Oefening 5 uit: parse ook eenvoudige types (int, float, bool voor true/false).
- Ontwerp
load_typed_config(path: str) -> dict[str, object]. - Onbekende waarden blijven strings.
- Gooi
ConfigErrormet duidelijke foutboodschappen en toon een korte, nette samenvatting in__main__.