Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 else plaatsen en altijd‑opruimen in finally of via with doen.
  • Fouten zelf signaleren met raise en, waar passend, her‑gooien met logging (re‑raise) of exception chaining gebruiken.
  • Eenvoudig en defensief valideren; kies tussen herstelbare en terminale fouten.
  • logging gebruiken i.p.v. print voor foutmeldingen.

Richtlijnen

  • Houd je try‑blok zo klein mogelijk (alleen de riskante regels).
  • Vang specifieke excepties; vermijd except: en te brede except 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 float eindigen.

Oefening 3 — Calculator met ^ (macht) en nette foutmeldingen Schrijf calc(a: float, op: str, b: float) -> float die + - * / ^ ondersteunt.

  • raise ZeroDivisionError bij deling door nul.
  • raise ValueError bij 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 ConfigError als 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 ConfigError met duidelijke foutboodschappen en toon een korte, nette samenvatting in __main__.