0%

Bestanden lezen en schrijven · oefening

Bestandsfouten bruikbaar melden

read_books werkt als aan de afspraken wordt voldaan: het pad bestaat, verwijst naar een leesbaar bestand en bevat UTF-8-tekst. Bij de overgang naar de buitenwereld gaat die afspraak soms niet op.

Twee fouten zijn hier voorspelbaar genoeg om hulp bij te bieden:

  • FileNotFoundError: er bestaat niets op het pad dat Python probeerde te openen;

  • UnicodeDecodeError: er zijn bytes, maar het is geen geldige UTF-8-tekst.

Geen van beide betekent dat read_books een lege lijst moet teruggeven. Een leeg bestand is geldig en bevat daadwerkelijk geen titels. Een ontbrekend of niet-decodeerbaar bestand is iets anders. Dat vermommen als “nul boeken” zou een geloofwaardige leugen opleveren.

Houd de herbruikbare functie eerlijk

Laat read_books(path) deze exceptions opwerpen. De functie heeft geen gebruikersinterface en kan niet weten of de aanroeper een opdrachtregelprogramma, een latere gegevensconverter of een test is. Een speciale zin teruggeven vanuit een functie die een lijst hoort op te leveren zou twee taken vermengen.

Vang de fouten op in main(), waar het programma eindelijk genoeg context heeft om iemand te vertellen wat die kan doen:

try:
    books = read_books(BOOKS_PATH)
except FileNotFoundError:
    print(f"Could not find {BOOKS_PATH}. Run this program from the project root.")
    return
except UnicodeDecodeError:
    print(f"Could not read {BOOKS_PATH} as UTF-8 text.")
    return

Druk na de twee afhandelingen Loaded 4 books. af met de werkelijke lengte. In latere lessen vervang je die tijdelijke succesmelding door opgeslagen uitvoer.

Vang alleen op wat je kunt herstellen

except Exception: zou ook een verkeerd gespelde variabele, foutieve berekening of een morgen geïntroduceerde bug opvangen. Het programma zou “bestandsprobleem” kunnen melden terwijl het bestand perfect is. Daardoor verdwijnt de oorspronkelijke traceback juist wanneer die het nuttigst is.

Gerichte foutafhandeling is niet bedoeld om een programma nooit te laten mislukken. Je verbetert ermee de fouten waarvan je de betekenis begrijpt, terwijl onbekende fouten zichtbaar blijven.

De fouttekst moet BOOKS_PATH bevatten. “File not found” benoemt alleen de soort fout. “Could not find data/books.txt; run from the project root” geeft een volgende stap — uitvoeren vanuit de projecthoofdmap — en sluit aan op de padregel uit de eerste les.

Waarom moet een ontbrekend bestand niet een lege lijst opleveren?

Implementeer de twee gerichte afhandelingen en de tijdelijke succesmelding.

Controleer vervolgens of je niet te veel opvangt. Spel tijdelijk een variabelenaam binnen read_books verkeerd, zodat er een NameError ontstaat, en voer het programma uit. Je wilt een traceback zien. Zie je in plaats daarvan een van je twee vriendelijke bestandsmeldingen, dan vangt de afhandeling meer op dan ze begrijpt. Zet de naam daarna terug.

Twijfel je of een afhandeling te breed is, vraag Monty dan: “Wat zou except Exception hier kunnen opvangen dat ik liever als traceback zie?” Die lijst is meestal langer dan mensen verwachten.

Opdracht

Werk main() bij zodat die:

  • read_books(BOOKS_PATH) aanroept;

  • FileNotFoundError opvangt, een melding afdrukt met BOOKS_PATH en de vervolgstap om vanuit de projecthoofdmap te starten, en daarna terugkeert; gebruik daarvoor de Engelse voorbeeldmelding met “project root”;

  • UnicodeDecodeError opvangt, een melding afdrukt met BOOKS_PATH en UTF-8, en daarna terugkeert;

  • anders Loaded N books. afdrukt met de echte lengte van de lijst.

Vang geen Exception of andere niet-gerelateerde programmeerfouten op.