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.
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.
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.
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)Controle mislukt Afgewezen: vanaf 1900 2020
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.
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.
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__)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.
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.
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.
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.
Maak relay(error): werp het ontvangen foutobject en geef een opgevangen ValueError ongewijzigd verder. Ook andere fouttypen mogen niet worden vervangen of verborgen.
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.
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.
raise Fouttype(bericht) begint een nieuw foutpad.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.
Voer je code uit en ontdek
wat je hebt gemaakt.
Je hoeft het niet in één keer goed te doen. Na het uitvoeren zie je hier welke stappen al kloppen.