← Python/Foutafhandeling
Les 5 van 8
MODULE 06 · 05◷ 28 min

Fouten werpen, doorgeven en vertalen

Na deze les kun je
  • Een ongeldige waarde met een echte fout weigeren.
  • Het oorspronkelijke foutobject ongewijzigd doorgeven.
  • Bij vertalen de oorzaak bewaren of de contextweergave bewust onderdrukken.

Een negatief aantal kan technisch prima worden vermenigvuldigd, maar toch ongeldig zijn voor jouw reservering. Soms moet je daarom zelf een fout aangeven. Op een andere plek wil je een technische fout juist vertalen naar een bruikbare melding, zonder de oorzaak kwijt te raken.

Zelf een fout werpen

Met raise geef je aan dat de gewone uitvoering niet verder kan. Achter het sleutelwoord staat een foutobject, bijvoorbeeld ValueError("aantal moet nul of hoger zijn"). De tekst tussen haakjes is het bericht; het fouttype bepaalt welke handler past.

Een foutobject is dus een waarde die je kunt bewaren en doorgeven. Een bericht printen is iets anders: daarna gaat het programma normaal verder. Wie jouw functie aanroept, moet een ongeldige uitkomst juist via de foutafhandeling kunnen herkennen.

Je kunt een opgevangen fout met except ValueError as error tijdelijk de naam error geven. Binnen die handler betekent een losstaande raise dat dezelfde fout verdergaat. Je maakt daarmee geen nieuw object met alleen hetzelfde bericht.

Bekijk hoe de jaarcontrole een eigen grens bewaakt, een mislukking meldt en de fout daarna doorgeeft. De buitenste handler beslist wat de gebruiker ziet. De geldige waarde hoeft niet langs die herstelroute.

Een eigen validatiefout melden en doorgeven
def require_year(year):
    try:
        if year < 1900:
            raise ValueError("vanaf 1900")
        return year
    except ValueError:
        print("Controle mislukt")
        raise

for year in [1899, 2020]:
    try:
        print(require_year(year))
    except ValueError as problem:
        print("Afgewezen:", problem)
Verwachte uitvoer
Controle mislukt
Afgewezen: vanaf 1900
2020

Een oorzaak bewaren

Een laag die invoer verwerkt, kent soms meer context dan de onderliggende conversie. Exceptionchaining verbindt een nieuwe fout met de oorspronkelijke oorzaak. Met raise RuntimeError("kan niet verwerken") from error geef je een nieuwe betekenis aan de mislukking en bewaar je het oorspronkelijke foutobject.

Een foutobject heeft eigenschappen die je met een punt kunt lezen. De eigenschap __cause__ verwijst bij deze expliciete vertaling naar de oorzaak. De onderstrepingen horen bij de naam: error.__cause__ leest die verwijzing, niet een kopie van de berichttekst.

In een traceback kan Python daardoor eerst de oorzaak en daarna de nieuwe fout tonen. Dat helpt wanneer een technische conversie diep in een programma mislukt. Een nieuwe ValueError(str(error)) met hetzelfde bericht bewaart die verwijzing naar het oorspronkelijke object niet.

Details uit de weergave houden

Met from None kun je de eerdere fout uit de standaardweergave van de nieuwe fout houden. De expliciete oorzaak is dan None. De oudere fout kan nog steeds in __context__ staan; deze vorm wist haar niet uit het foutobject.

De eigenschap __suppress_context__ geeft aan dat Python die impliciete context niet automatisch moet tonen. In het voorbeeld leveren zowel een expliciete oorzaak als from None hiervoor True op. Het verschil zit in __cause__: eenmaal een ValueError, eenmaal None.

Met type(error).__name__ lees je de eigenschap __name__, de typenaam als tekst. Daardoor toont het voorbeeld bijvoorbeeld ValueError of NoneType.

Een oorzaak en onderdrukte weergave onderscheiden
def parse_year(text, hide):
    try:
        return int(text)
    except ValueError as problem:
        if hide:
            raise RuntimeError("geen compleet jaartal") from None
        raise RuntimeError("geen compleet jaartal") from problem

for hide in [False, True]:
    try:
        parse_year("oud", hide)
    except RuntimeError as error:
        print(type(error.__cause__).__name__, error.__suppress_context__)
Verwachte uitvoer
ValueError True
NoneType True

Kies deze vorm bewust voor de presentatie, niet als manier om alle diagnostische informatie te verwijderen. Een buitenste handler kan de fout nog steeds onderzoeken. Een onbedoeld breed afgevangen fout wordt door een mooiere melding niet ineens een verwachte situatie.

Veelgemaakte fout: de oorzaak opnieuw bouwen

Alleen het bericht overnemen lijkt netjes, maar levert een ander foutobject op. Daarmee kunnen de oorspronkelijke locatie en de verbinding met de mislukte bewerking verloren gaan. Geef bij een vertaling het werkelijk opgevangen object aan from mee.

Bij gewoon doorgeven is een losstaande raise binnen de handler de duidelijkste keuze. Gebruik die niet buiten een actieve handler: daar is geen opgevangen fout om opnieuw door te geven. Je eigen validatiefout krijgt juist wel een expliciet nieuw foutobject.

Jouw foutgrenzen

De opdrachten onderscheiden drie bedoelingen: ongeldige waarden weigeren, dezelfde fout doorgeven en alleen ValueError vertalen. Andere fouttypen blijven ongewijzigd doorgaan. De controles onderzoeken echte objectverwijzingen en context; een teruggegeven tuple met foutteksten is geen geworpen fout.

AAN DE SLAG 0/4
1

Ongeldige waarden zelf weigeren

Maak positive_count(number): geef een geheel getal van nul of hoger onveranderd terug. Werp bij een negatief getal ValueError met exact het bericht aantal moet nul of hoger zijn.

2

Dezelfde fout doorgeven

Maak relay(error): werp het ontvangen foutobject en geef een opgevangen ValueError ongewijzigd verder. Ook andere fouttypen mogen niet worden vervangen of verborgen.

3

Een oorzaak bij de nieuwe fout bewaren

Maak translate(error): werp error, vang uitsluitend ValueError af en vertaal die naar RuntimeError met bericht kan niet verwerken. Bewaar het werkelijk ontvangen foutobject als expliciete oorzaak. Andere typen blijven ongewijzigd.

4

De contextweergave bewust onderdrukken

Maak hide_details(error): vertaal uitsluitend een geworpen ValueError naar RuntimeError met bericht ongeldige invoer, met from None. De oude fout blijft als context beschikbaar; andere fouttypen blijven ongewijzigd.

Onthoud dit

  • raise Fouttype(bericht) begint een nieuw foutpad.
  • Een losstaande raise geeft de opgevangen fout door.
  • from error bewaart de oorzaak; from None verandert de standaardweergave.

Hierna geef je fouten uit jouw eigen domein een herkenbaar type.

main.py
UitvoerPython
›
›_

Hier komt je resultaat.

Voer je code uit en ontdek
wat je hebt gemaakt.

0/4 stappen
EVEN MEEKIJKEN

Bekijk hoe het kan.

Je mag de oplossing bekijken. Deze poging telt dan niet mee als afgeronde les. Met Reset kun je daarna opnieuw zelf oefenen.