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

Een eigen foutcategorie voor aantallen

Na deze les kun je
  • Een eenvoudig eigen fouttype van ValueError laten afstammen.
  • Conversiefouten en domeinfouten met hun eigen reden onderscheiden.
  • De eigen categorie met isinstance herkennen en gericht afhandelen.

Een conversiefout en een ongeldig aantal kunnen allebei ValueError heten. Toch wil een aanroeper misschien alleen problemen met aantallen herstellen, en andere fouten laten opvallen. Een eigen fouttype maakt dat onderscheid expliciet, zonder berichten als protocol te hoeven ontleden.

Een naam voor jouw foutcategorie

Een klasse beschrijft een soort object. Voor een eenvoudig eigen fouttype heb je maar een kleine klassedefinitie nodig: class SettingError(ValueError): met daaronder een ingesprongen pass. pass vult het verplichte blok zonder extra handeling uit te voeren.

De nieuwe fout is een subklasse van ValueError. Via overerving krijgt zij het bestaande foutgedrag, waaronder het bewaren van een bericht. Je kunt dus meteen SettingError("ongeldige instelling") maken en dat object met raise werpen.

Voor deze les blijft de klasse bewust klein. Eigen attributen, methoden en uitgebreidere klassedefinities komen in de volgende module. Je gebruikt hier alleen de herkenbare categorie en het foutgedrag dat al bestaat.

Eerst een zelfstandig voorbeeld

De instellingenlezer vertaalt een mislukte conversie naar SettingError en bewaart de oorzaak. De buitenste handler vangt juist die eigen categorie af. Voorspel welke invoer een gewoon getal oplevert en welke invoer langs de handler gaat.

Een eigen type met de oorspronkelijke oorzaak
class SettingError(ValueError):
    pass

def parse_timeout(text):
    try:
        return int(text)
    except ValueError as problem:
        raise SettingError("timeout is geen geheel getal") from problem

for text in ["12", "snel"]:
    try:
        print(parse_timeout(text))
    except SettingError as error:
        print("Afgewezen:", error)
Verwachte uitvoer
12
Afgewezen: timeout is geen geheel getal

De handler hoeft niet te zoeken naar een woord in het bericht om de categorie te herkennen. Het type draagt die betekenis. De tekst blijft bedoeld om de reden aan een mens uit te leggen.

Een basistype blijft ook passen

Een handler voor ValueError past ook bij SettingError, omdat die daarvan afstamt. Dat is handig wanneer een buitengrens alle ongeldige waarden hetzelfde behandelt. Een plek die uitsluitend instellingsproblemen verwacht, kiest juist het specifiekere type.

Een basishandler past ook bij de subklasse
class SettingError(ValueError):
    pass

try:
    raise SettingError("instelling ontbreekt")
except ValueError as error:
    print("Brede handler:", error)
    print(isinstance(error, SettingError))
Verwachte uitvoer
Brede handler: instelling ontbreekt
True

Dit is dezelfde volgorderegel als bij IndexError en LookupError uit les 3. Een brede handler vóór een specifieke handler kan de eigen fout al onderscheppen. Alleen een nieuwe klassenaam toevoegen verandert die volgorde niet.

Herkennen zonder tekstvergelijking

Met isinstance controleer je of een object bij een type of een daarvan afgeleid type hoort. isinstance(error, SettingError) is waar voor een gewone SettingError én voor een specifiekere subklasse. Een gewone ValueError hoort daardoor nog niet bij de eigen categorie.

Een vergelijking als type(error) is SettingError vraagt het precieze type en sluit verdere subklassen uit. Dat verschil is van belang bij de herkenningsfunctie in de opdracht. Die moet de hele eigen categorie accepteren, niet uitsluitend één exacte klasse.

Veelgemaakte fout: te veel vertalen

Stel dat je eerst tekst omzet en daarna controleert of het aantal niet negatief is. Een brede except ValueError rond beide stappen vangt ook jouw eigen CountError uit de tweede stap. Je zou dan ten onrechte een geldig geschreven negatief getal als onleesbare tekst kunnen melden.

Houd daarom de conversie en de domeincontrole uit elkaar. Alleen een mislukte int wordt vertaald naar CountError("geen geheel getal") met de oorspronkelijke oorzaak. Een negatief getal krijgt zijn eigen reden en blijft die reden behouden.

Jouw categorie voor aantallen

De starter bevat CountError, maar de basisklasse moet nog passend worden gemaakt. Laat haar van ValueError afstammen en gebruik haar daarna voor de afgesproken fouten. Nul is geldig; negatieve aantallen zijn dat in deze oefening niet.

count_status ontvangt een functie als argument. Alleen jouw CountError levert de afgesproken afwijzingstekst op. Een gewone ValueError of een andere onverwachte fout moet zichtbaar blijven voor de aanroeper.

AAN DE SLAG 0/4
1

Een eigen categorie en domeingrens

Laat CountError van ValueError afstammen. Maak require_count(number): geef nul en positieve gehele getallen terug; werp bij een negatief getal een echte CountError met bericht negatief aantal.

2

Conversie en domeincontrole scheiden

Maak parse_count(text): zet tekst om met int en weiger daarna negatieve aantallen als CountError met negatief aantal. Vertaal alleen een mislukte conversie naar CountError met geen geheel getal, vanuit de werkelijk opgevangen ValueError.

3

De hele eigen categorie herkennen

Maak is_count_error(error) die een echte boolean teruggeeft: True voor CountError en verdere subklassen daarvan, False voor gewone ValueError en andere fouten.

4

Alleen het domeinprobleem afhandelen

Maak count_status(operation): roep operation() aan. Geef bij succes goed: <waarde> terug en bij CountError ongeldig: <bericht>. Gewone ValueError en andere onverwachte fouten mogen niet door die handler verdwijnen.

Onthoud dit

  • Een klein eigen fouttype geeft een herkenbare betekenis aan een mislukking.
  • Een handler voor de basisklasse past ook bij haar subklassen.
  • isinstance herkent de categorie; houd conversie en domeincontrole gescheiden.

Hierna bewaar je bruikbare informatie zonder onverwachte fouten stil te verbergen.

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.