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

Inhoud

  1. Kennismaking
  2. Invoer en uitvoer
  3. Selecties
  4. Lussen en iteraties
  5. Lijsten
  6. Functies
  7. Foutafhandeling
  8. Bestanden
  9. Modules & venv
  10. Basis testen en debuggen
  11. Eindproject

Werkboek — Hoofdstuk 1: Variabelen en basisberekeningen

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

  • Werken met variabelen (namen kiezen, toekennen).
  • Rekenexpressies gebruiken (optellen, aftrekken, vermenigvuldigen, delen, macht).
  • Invoer omzetten naar het juiste type (str → float/int).
  • Resultaten netjes tonen (f-strings, afronden).

Oefening 1 — Cirkel: omtrek en oppervlakte Schrijf een programma dat de gebruiker om de straal (radius) vraagt. Bereken:

  • de omtrek: 2 · π · r
  • de oppervlakte: π · r^2 Eisen:
  • Gebruik math.pi.
  • Toon beide resultaten met duidelijke tekst.
  • Gebruik f-strings.

Oefening 2 — BMI met afronding Vraag de gebruiker om lengte (in meters) en gewicht (in kilogram). Bereken de BMI: gewicht / (lengte^2). Eisen:

  • Rond af op 1 decimaal in de uitvoer (bijv. 23.4).
  • Toon een korte tekst zoals: "BMI is 23.4".

Oefening 3 — BTW 9% Vraag een bedrag (exclusief btw) en bereken de prijs inclusief 9% btw. Eisen:

  • Rond netjes af op 2 decimalen in de uitvoer.
  • Gebruik een variabele voor het btw-percentage (bijv. vat_rate = 0.09).

Oefening 4 — Variabelen ruilen (swap) Maak twee variabelen a en b met getalwaarden. Wissel hun waarden om. Eisen:

  • Laat eerst de waarden voor het wisselen zien, daarna erna.
  • Tip: je mag in Python een tijdelijke variabele gebruiken of Python’s tuple-swap (a, b = b, a).

Oefening 5 — Kortingen stapelen Je hebt een oorspronkelijke prijs (bijv. 80.0). Pas eerst 10% korting toe, daarna 5% extra korting op het nieuwe bedrag. Eisen:

  • Bereken ook wat één enkele korting van 15% zou geven.
  • Toon beide resultaten en laat zien of ze gelijk zijn of verschillen.

Oefening 6 — Kommagetallen en precisie Onderzoek het gedrag van floats met 0.1 + 0.2. Eisen:

  • Print het resultaat van 0.1 + 0.2 en vergelijk met 0.3.
  • Toon vervolgens hetzelfde resultaat met round(..., 2).
  • Schrijf in een comment je observatie (in het Engels in de code of in het Nederlands eronder).

Uitdaging (optioneel) — Rechthoek helper Schrijf een klein script waarin je:

  • width en height vraagt (float).
  • area en perimeter uitrekent (area = width * height, perimeter = 2 * (width + height)).
  • de resultaten toont met duidelijke labels en net afgerond (2 decimalen).

Werkboek — Hoofdstuk 2: Invoer en uitvoer

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

  • Invoer lezen met input() en tekst schoonmaken met .strip().
  • Typeconversie toepassen (int, float) en waar nodig komma → punt omzetten.
  • Resultaten netjes weergeven met print() en f-strings (incl. formaat-specificaties).
  • Uitvoer beheren met sep, end, flush, en schrijven naar stderr.
  • Basisbewustzijn van Unicode/encodering en command-line argumenten (teaser).

Richtlijnen

  • Gebruik duidelijke, Engelstalige variabelen- en functienamen.
  • Toon duidelijke labels in de uitvoer; formatteer geldbedragen en percentages net.
  • Als een opdracht het expliciet vraagt: sta komma als decimaalteken toe door te vervangen met een punt.

Oefening 1 — Begroeting Vraag de gebruiker om voornaam en print: Hello, <First>! met een f-string. Trim spaties.

Oefening 2 — Volledige naam Vraag voornaam en achternaam (twee keer input). Print twee varianten:

  • Last, First
  • First Last Gebruik f-strings.

Oefening 3 — Bedrag netjes tonen (komma of punt) Vraag een bedrag (tekst kan komma of punt bevatten). Zet om naar float (vervang komma door punt) en print Amount: <bedrag> met 2 decimalen.

Oefening 4 — Percentage format Vraag een decimaal getal (bijv. 0.075) en druk het af als percentage met precies één decimaal, bijv. Rate: 7.5%.

Oefening 5 — Kleine bon (uitlijning) Vraag drie keer: productnaam, aantal (int), prijs per stuk (float, komma toegestaan). Print daarna een kleine tabel:

  • Kopregel met kolommen Item, Qty, Price, Total.
  • Eén regel per product met nette uitlijning en prijzen met 2 decimalen. Tip: gebruik f-string veldbreedtes zoals in het boek.

Oefening 6 — Print parameters Print de letters a, b, c op één regel, gescheiden door , , en eindig met ! (dus: a, b, c!). Gebruik print(..., sep=..., end=...).

Oefening 7 — Voortgangspunten Print vijf punten ..... zonder newlines ertussen, door end='' en flush=True te gebruiken in een kleine herhaling. (Je mag vijf print-aanroepen uitschrijven of een eenvoudige range‑lus gebruiken.)

Oefening 8 — Foutmelding via stderr Vraag om een geheel getal. Als de conversie met int(...) faalt, schrijf een bericht naar stderr met een duidelijke waarschuwing, anders print OK: <n> naar stdout.

Oefening 9 — Unicode check Print een korte string met speciale tekens, bijvoorbeeld: café • naïve • € • λ. Leg kort in een comment uit wat je verwacht te zien.

Oefening 10 — Command-line argument (teaser) Schrijf een script dat een naam uit sys.argv[1] leest als die aanwezig is, anders world gebruikt. Print Hello, <name>!.

Uitdaging (optioneel) — Totaal met BTW en korting Vraag amount (float, komma toegestaan) en discount (percentage als 0–100). Bereken: eerst korting toepassen, dan 21% btw toevoegen. Print een keurig overzicht met:

  • Amount:, Discount:, After discount:, VAT (21%):, Total: Formatteer bedragen met twee decimalen en het percentage met één decimaal.

Werkboek — Hoofdstuk 3: Selecties (if / elif / else)

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

  • Voorwaarden schrijven met vergelijkings- en logische operatoren.
  • Beslissingen nemen met if/elif/else en met de voorwaardelijke expressie (ternary).
  • Begrijpen van truthiness (lege waarden zijn onwaar) en valkuilen vermijden.

Richtlijnen

  • Gebruik duidelijke variabelenamen (Engels).
  • Houd je aan de grenswaarden zoals gevraagd; benoem je keuzes in comments.
  • Print duidelijke output zodat een gebruiker begrijpt wat er gebeurt.

Oefening 1 — Basis if Schrijf een script dat een geheel getal n leest en print:

  • "even" als n deelbaar is door 2,
  • anders "odd". Gebruik een enkele if/else.

Oefening 2 — Leeftijdscategorieën Vraag een leeftijd (integer) en print precies één van: "minor" (< 18), "adult" (18–64), "senior" (65+). Gebruik elif in de juiste volgorde.

Oefening 3 — Rapportcijfer naar label Lees een decimaal cijfer 0–10 en print: "insufficient" (< 5.5), "sufficient" (5.5–6.9), "good" (7.0–8.4), "excellent" (8.5–10). Zorg dat elke invoer in 0..10 in precies één categorie valt.

Oefening 4 — Login-indicatie (zonder echte beveiliging) Vraag username en password en print "Welcome!" als ze exact "admin" en "secret" zijn, anders "Access denied". Gebruik een enkele if/else met and.

Oefening 5 — Korting met lidmaatschap Lees een bedrag amount (float) en vraag of iemand lid is (antwoord yes of no). Regels:

  • 10% korting als lid én amount >= 100.
  • Anders 5% korting als amount >= 150.
  • Anders 0%. Print het kortingspercentage en het bedrag na korting (2 decimalen).

Oefening 6 — Truthiness en invoer Vraag een zoekterm (string). Print:

  • "Empty query" als de invoer leeg is (na strip()),
  • anders "Searching for ''...". Gebruik de ternary expression.

Oefening 7 — Kettingvergelijking Lees een integer x en print True of False of x in het bereik 10..20 (inclusief) ligt, met een kettingvergelijking. Print geen extra tekst.

Oefening 8 — Guard clause (functie) Schrijf een functie shipping_cost(country: str, weight_kg: float) -> float met regels uit het boek:

  • Als weight_kg <= 0: raise ValueError.
  • NL: 4.50 (<= 2 kg) anders 6.75; BE: 5.20 (<= 2 kg) anders 7.40; overige: 9.90. Schrijf een klein __main__-blok dat 2–3 voorbeelden print.

Oefening 9 — Wachtwoordsterkte-indicatie (eenvoudig) Lees een wachtwoord (string) en geef één label:

  • "weak" als lengte < 6,
  • "medium" als lengte 6–9,
  • "strong" als lengte >= 10. Gebruik alleen lengte als criterium in deze oefening. Toon ook de lengte in de output.

Oefening 10 — Netto prijs met btw‑optie Lees amount (float) en type (string: incl of excl). Als type == "incl", haal 21% btw eraf en toon netto; als excl, tel 21% btw erbij. Gebruik duidelijke prints en formatteer met 2 decimalen. Vang geen invoerfouten in deze oefening; focus op selecties.

Uitdaging (optioneel) — Kalenderdag naar type dag Vraag een dagnaam (bijv. "monday"/"tuesday" etc., case-insensitive). Print "weekend" voor zaterdag/zondag, anders "weekday". Gebruik normalisatie (lower()) en een compacte voorwaarde (bijv. in op een set of tuple).

Werkboek — Hoofdstuk 4: Lussen en iteraties

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

  • Herhalen met while en tellen/doorlopen met for.
  • range(start, stop, step) effectief gebruiken.
  • Begrijpen en toepassen van break en continue.
  • Handige helpers gebruiken: enumerate, iteratie over dicts, geneste lussen.
  • Het patroon for-else inzetten bij zoekproblemen.

Richtlijnen

  • Gebruik duidelijke variabelen- en functienamen (Engels).
  • Print nette, betekenisvolle output zodat je resultaat te controleren is.
  • Hou je lussen klein en leesbaar; vermijd onnodige continue/break.

Oefening 1 — Tellen met range Print de getallen 1 t/m 10 op één regel, gescheiden door spaties. Gebruik een for-lus met range.

Oefening 2 — Som 1..n (accumulatie) Vraag een positief geheel getal n (ga uit van geldige invoer in deze oefening) en bereken de som van 1..n met een for-lus. Print de som.

Oefening 3 — While-teller omlaag Print een aftelling van 5 naar 1 met een while-lus en eindig met Liftoff!.

Oefening 4 — Alleen even getallen (continue) Print de even getallen van 1..20 met een while-lus. Gebruik continue om oneven getallen over te slaan.

Oefening 5 — Eerste veelvoud vinden (for-else) Zoek in 1..50 naar het eerste getal dat deelbaar is door 7 én 5. Print Found: <getal> als het bestaat; anders No match. Gebruik een for met een else-deel (dus break bij succes, anders valt het else-blok in).

Oefening 6 — Genummerde lijst (enumerate) Gegeven een lijst names = ["Ava", "Bo", "Cid", "Dia"]. Print elke naam genummerd vanaf 1 in de vorm 1. Ava, 2. Bo, ... Gebruik enumerate(..., start=1).

Oefening 7 — Itereren over dict Gegeven user = {"name": "Liam", "age": 31, "city": "Rotterdam"}. Print elke sleutel en waarde op een eigen regel in de vorm name: Liam.

Oefening 8 — Tafel van vermenigvuldiging (genest) Print een 10×10 vermenigvuldigingstafel (1..10 × 1..10). Gebruik twee geneste for-lussen en maak kolommen netjes met een breedte van 4 tekens. Tip: print(f"{value:>4}", end="") en na een rij print() voor de newline.

Oefening 9 — Invoer tot leeg (sentinel) Lees regels in van de gebruiker tot een lege regel wordt ingevoerd. Tel hoeveel niet-lege regels gegeven zijn en print Count: <aantal>. Gebruik een while True-lus met break.

Oefening 10 — Filter en transformeer Gegeven nums = [3, 8, 1, 7, 2, 10, 5].

  • Bouw met een for-lus een nieuwe lijst evens met alleen de even getallen.
  • Bouw met een tweede for-lus een lijst squares met kwadraten van alle getallen uit nums. Print beide lijsten. (Gebruik hier nog géén list comprehensions.)

Uitdaging (optioneel) — FizzBuzz 1..100 Print de getallen 1..100, maar vervang veelvouden van 3 door Fizz, van 5 door Buzz, en van 3 én 5 door FizzBuzz. Alles op aparte regels. Gebruik een for-lus en duidelijke if/elif-logica.

Werkboek — Hoofdstuk 5: Lijsten (list)

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

  • Lijsten maken en lezen: literals, list(...), lengte, indexen, slices.
  • Lijsten muteren: toekennen aan index/slice, append, extend, insert, remove, pop, del, clear.
  • Zoeken en itereren: in, index, count, for, enumerate.
  • Sorteren: list.sort, sorted, reverse, key.
  • Kopiëren vs aliasing; 2D-lijsten (valkuil vermenigvuldiging); lijstcomprehensies.

Richtlijnen

  • Gebruik duidelijke naamgeving (Engels) en toon heldere output waar zinvol.
  • Schrijf kleine, goed-gestructureerde stukjes code; voeg korte comments toe bij keuzes.
  • Vermijd het muteren van een lijst terwijl je er rechtstreeks over iterereert (tenzij expliciet gevraagd en veilig gemaakt).

Oefening 1 — Basis maken en lezen Maak een lijst fruits = ["apple", "banana", "cherry"].

  • Print de lengte.
  • Print het eerste en laatste element met index en met negatieve index.

Oefening 2 — Slices Gegeven nums = [10, 20, 30, 40, 50, 60]:

  • Print nums[1:4] en nums[:3] en nums[3:].
  • Maak rev als omgekeerde kopie met een slice en print die.

Oefening 3 — Mutatie met index en slice Start met items = [1, 2, 3, 4, 5].

  • Vervang het element op index 1 door 20.
  • Vervang de slice items[2:4] door [7, 8, 9].
  • Voeg vervolgens met slice-insert op positie 2 de waarden [100, 101] toe (zonder te verwijderen). Print het resultaat na elke stap.

Oefening 4 — Toevoegen en verwijderen Start met colors = ["red"].

  • Voeg met append en extend respectievelijk "green" en "blue", "green" toe.
  • Verwijder één keer "green" met remove (let op: verwijdert de eerste match).
  • Gebruik pop() om het laatste element te verwijderen en te printen.
  • Toon de uiteindelijke lijst.

Oefening 5 — Zoeken en membership Gegeven letters = ["a", "b", "a", "c", "a"]:

  • Print of "b" in de lijst zit (Booleans).
  • Print de index van de eerste "a" en het aantal "a"'s.

Oefening 6 — Iteratie en enumerate Gegeven names = ["Ava", "Bo", "Cid"]:

  • Print elke naam op een aparte regel.
  • Print daarna genummerd met enumerate(..., start=1) in de vorm 1. Ava etc.

Oefening 7 — Sorteren met key en reverse Gegeven names = ["bo", "Ava", "cid", "Dia"]:

  • Print een nieuwe alfabetisch gesorteerde lijst, hoofdletterongevoelig.
  • Print een aflopende sortering op lengte (langste eerst), bij gelijke lengte alfabetisch. Tip: gebruik sorted(names, key=str.lower) en een key met een tuple, plus reverse=True waar nodig.

Oefening 8 — Kopiëren vs. aliasing

  • Maak original = [1, 2, 3] en zet alias = original.
  • Voer alias.append(4) uit en print beide.
  • Maak vervolgens een échte kopie met copy = original[:] en voeg 5 toe aan copy. Print beide om het verschil te tonen.

Oefening 9 — 2D‑lijst: vermenigvuldigingsvalkuil

  • Maak een 2×3-matrix met nullen op een foute manier: m = [[0] * 3] * 2.
  • Zet m[0][0] = 1 en print m — observeer de bug.
  • Maak dezelfde matrix correct met een list comprehension en herhaal de wijziging; toon nu het juiste gedrag.

Oefening 10 — Lijstcomprehensies (filter + transform)

  • Bouw met een list comprehension een lijst squares met de kwadraten van 0..10.
  • Bouw met een comprehension een lijst evens met de even getallen uit range(0, 21).
  • Bouw met een comprehension labels "even"/"odd" voor 0..5 met een inline voorwaardelijke expressie.

Uitdaging (optioneel) — Unieke elementen met behoud van volgorde Schrijf een functie unique_in_order(items) die de eerste keer dat een item voorkomt behoudt en latere duplicaten overslaat, waarbij de oorspronkelijke volgorde behouden blijft.

  • Voorbeeld: unique_in_order(["a","b","a","c","b"]) → ["a","b","c"].
  • Gebruik geen set voor directe conversie, want dat verliest volgorde; gebruik een hulp-set() om gezien te markeren en bouw een nieuwe lijst op.

Werkboek — Hoofdstuk 6: Functies en modulair denken

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

  • Functies definiëren met def en aanroepen met argumenten (positional/keyword).
  • Waarden teruggeven met return (één of meerdere via tuple) en vroegtijdig terugkeren (guard).
  • Parameters met standaardwaarden en eenvoudige validatie.
  • Basisbegrip van scope (LEGB), en van mutabele argumenten vs. kopiëren.
  • Docstrings en type hints gebruiken voor duidelijkheid.

Richtlijnen

  • Kies duidelijke, Engelstalige functienamen en parameters.
  • Houd functies klein en gericht: één taak per functie.
  • Schrijf pure functies waar dat kan; laat I/O (print/input) buiten de kernlogica.

Oefening 1 — Begroeting als functie Schrijf een functie greet(name: str) -> str die een begroetingstekst teruggeeft, bijv. "Hello, Ava!". Print 2 voorbeelden in een __main__-blok.

Oefening 2 — Oppervlakte cirkel Schrijf circle_area(radius: float) -> float die de oppervlakte teruggeeft met math.pi. Voeg een korte docstring en type hints toe. Test met radius 0, 1.5 en 2.0.

Oefening 3 — Vermogen met standaard exponent Schrijf power(base: float, exp: int = 2) -> float. Toon voorbeeldaanroepen met én zonder exp, en één met keyword-argumenten.

Oefening 4 — Vroege return (guard) Schrijf safe_div(a: float, b: float) -> float | None die None teruggeeft als b == 0, anders het quotiënt. Print resultaten voor (10,2) en (3,0).

Oefening 5 — Meerdere waarden teruggeven Schrijf min_max_avg(values: list[float]) -> tuple[float, float, float] die (min, max, avg) teruggeeft. Bepaal zelf wat te doen bij lege lijst (bijv. raise ValueError of (None, None, None)); documenteer je keuze in de docstring.

Oefening 6 — Invoer-helper (zonder print in kernfunctie) Schrijf parse_float(text: str) -> float | None die een string naar float probeert te converteren (komma→punt toestaan). Geef None terug bij ongeldige invoer. Schrijf in __main__ een klein scriptje dat de gebruiker om invoer vraagt, parse_float aanroept en dan óf het getal print óf een nette foutmelding.

Oefening 7 — Mutabele argumenten: muteren vs. kopiëren Schrijf twee functies:

  • append_exclamation_inplace(items: list[str]) -> None die het lijstargument wijzigt door "!" toe te voegen.
  • with_exclamation_copy(items: list[str]) -> list[str] die een nieuwe lijst teruggeeft met een extra "!", zonder de inputlijst te wijzigen. Demonstreer in een __main__-blok het verschil met een voorbeeldlijst.

Oefening 8 — Scope (LEGB) demonstratie Schrijf een mini-demonstratie met een globale variabele x = 10 en een functie demo() die lokaal x = 5 definieert en print. Print buiten de functie daarna ook x. Schrijf in een comment (Nederlands) wat je observeert. (Gebruik geen global in deze oefening.)

Oefening 9 — Docstring en help Schrijf een functie slugify(text: str) -> str met een duidelijke docstring (korte beschrijving, voorbeeld). Print slugify.__doc__ en roep help(slugify) aan in een __main__-blok (laat gewoon zien dat het werkt; de daadwerkelijke weergave kan per omgeving verschillen).

Oefening 10 — Mutabel standaardargument (valkuil en oplossing) Demonstreer kort het probleem:

  • Schrijf def add_item_bad(item, bucket=[]) die item toevoegt en bucket teruggeeft. Roep meerdere keren aan en toon het onverwachte gedrag.
  • Schrijf daarna de correcte variant def add_item(item, bucket=None) die binnenin een nieuwe lijst maakt als bucket is None. Geef een korte Nederlandse toelichting in comments.

Uitdaging (optioneel) — Refactor naar functies Begin met een klein script dat een "bon" print (producten met qty en price, totalen). Refactor het naar:

  • line_total(qty: int, price: float) -> float
  • format_line(name: str, qty: int, price: float) -> str
  • grand_total(items: list[tuple[str,int,float]]) -> float
  • render_receipt(items: list[tuple[str,int,float]]) -> str Zorg dat render_receipt géén print gebruikt maar een string teruggeeft. Toon het resultaat in __main__.

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__.

Werkboek — Hoofdstuk 8: Bestanden lezen en schrijven

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

  • Veilig werken met with open(...) en tekst‐encodering (encoding="utf-8").
  • Leespatronen voor tekst: read(), regels itereren, readline(), read(n).
  • Schrijfpatronen: write, writelines, newlines en newline‑parameter.
  • Paden met pathlib.Path: paden samenstellen, directories maken, globben.
  • Binaire I/O (chunks), defensief werken en veelvoorkomende valkuilen.

Richtlijnen

  • Gebruik with voor alle bestandsoperaties.
  • Specificeer bij tekstbestanden encoding="utf-8" expliciet.
  • Gebruik pathlib.Path waar zinvol i.p.v. alleen stringpaden.
  • Voeg zelf \n toe bij write; print(..., file=f) voegt standaard een newline toe (tenzij end is aangepast).

Oefening 1 — Merge .txt bestanden Schrijf een script dat alle .txt‑bestanden in een gegeven directory samenvoegt tot all.txt. Zet tussen ieder bronbestand een lege regel. Gebruik pathlib.Path.glob("*.txt").

Oefening 2 — tail(path, n) Implementeer een functie tail(path: str | Path, n: int) -> list[str] die de laatste n regels van een tekstbestand teruggeeft (zonder trailing newlines). Efficiënt genoeg voor middelgrote bestanden (je mag het hele bestand inlezen en de laatste n regels nemen).

Oefening 3 — copy_file (binair) Schrijf copy_file(src: str | Path, dst: str | Path, chunk_size: int = 8192) -> None die binaire data kopieert in chunks. Gebruik rb/wb en een lus met read(chunk_size).

Oefening 4 — grep‑achtig filter (case‑insensitive) Schrijf een functie grep_ci(path: str | Path, needle: str) -> None die regels print die needle (case‑insensitive) bevatten. Open met errors="replace" zodat corrupte encodering niet crasht.

Oefening 5 — CSV lezen (naïef) en net printen Gegeven een CSV‑bestand items.csv met kolommen name,qty,price. Lees het naïef met split(',') (weet: dit is niet robuust voor echte CSV). Print dan een tabel met nette kolombreedtes en een grand total.

Oefening 6 — JSON schrijven en lezen Schrijf twee helpers:

  • write_config(path: Path, data: dict) -> None die JSON schrijft met ensure_ascii=False, indent=2.
  • read_config(path: Path) -> dict die leest en het dict teruggeeft. Schrijf een __main__‑blok dat een klein config‑dict schrijft en daarna weer leest en een veld print. Vang FileNotFoundError en json.JSONDecodeError met duidelijke meldingen.

Oefening 7 — Atomisch schrijven Schrijf een functie atomic_write_text(path: Path, text: str) -> None die eerst naar path.with_suffix(path.suffix + ".tmp") schrijft en daarna os.replace gebruikt om atomisch te vervangen. Voeg encoding toe.

Oefening 8 — Newline normalisatie Schrijf write_unix_newlines(path: Path, lines: list[str]) -> None die altijd Unix‑newlines (\n) schrijft, ongeacht platform. Gebruik newline='\n' bij open en writelines.

Oefening 9 — Safe read_text Schrijf safe_read_text(path: Path) -> str | None die de inhoud leest (utf‑8) of None teruggeeft bij FileNotFoundError of PermissionError, met een vriendelijke printmelding.

Oefening 10 — Directory listing met groottes Schrijf een script dat alle items in een directory print met hun type (file/dir) en voor files ook de grootte in bytes. Toon onderaan het totaal aantal files en het totale aantal bytes. Gebruik Path.iterdir().

Uitdaging (optioneel) — Mini To‑Do CLI met bestand Maak een klein CLI‑programma dat een tekstbestand todo.txt gebruikt in de huidige directory.

  • add <text> voegt een regel toe.
  • list toont genummerde regels.
  • done <n> markeert item n als gedaan door het te verwijderen of te prefixen met [x] (kies één en beschrijf in een comment je keuze). Gebruik with en encoding="utf-8"; onthoud dat het bestand niet hoeft te bestaan bij de eerste run.

Werkboek — Hoofdstuk 9: Modules en virtuele omgevingen

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

  • Werken met modules en pakketten (packages) en deze importeren.
  • Het importpad (sys.path) begrijpen en het __name__ == "__main__"-patroon toepassen.
  • Een mini-tour door de standaardbibliotheek (math, random, datetime, pathlib).
  • Basisgebruik van pip en virtuele omgevingen (conceptueel/uitvoering buiten dit document).
  • Veelvoorkomende valkuilen vermijden (naamconflicten, star-imports, verkeerde werkdirectory).

Richtlijnen

  • Gebruik expliciete imports (import package of from package import name), vermijd from module import *.
  • Schrijf duidelijke, Engelstalige modulenaam- en functienamen.
  • Voor CLI-voorbeelden: voeg waar zinvol een if __name__ == "__main__":-blok toe.
  • Voor oefeningen met pip/venv: schrijf de commando’s en voorbeeldcode; uitvoeren doe je lokaal in je eigen omgeving.

Oefening 1 — Eigen module importeren (temperature) Maak temperature.py met twee functies:

  • c_to_f(c: float) -> float
  • f_to_c(f: float) -> float Schrijf een apart script app.py dat from temperature import c_to_f, f_to_c gebruikt en twee voorbeelden print.

Oefening 2 — import module vs. from module import name Schrijf twee varianten van een script dat math.pi print:

  • met import math en gebruik math.pi;
  • met from math import pi en gebruik pi. Schrijf kort in een comment wat het praktische verschil is in gebruik/namespace.

Oefening 3 — __name__ == "__main__" Breid temperature.py uit met een __main__-blok dat een optionele command-line parameter leest (sys.argv[1] als Celsius, anders 0.0) en de Fahrenheit-waarde print. Test door het bestand direct te runnen.

Oefening 4 — Het importpad bekijken Schrijf show_path.py dat alle paden in sys.path print (één per regel). Run het script vanuit verschillende werkdirectories en observeer de eerste entries. Noteer in comments wat je ziet.

Oefening 5 — Eenvoudig package: calc/ Maak een map calc/ met:

  • __init__.py (mag leeg, of exporteer add, sub via __all__).
  • ops.py met functies add(a, b), sub(a, b), mul(a, b), div(a, b) (gooi ZeroDivisionError bij b == 0). Schrijf main.py dat from calc.ops import add, div gebruikt en twee voorbeelden print.

Oefening 6 — Relatieve import binnen package Voeg in calc/cli.py een functie main() toe die from .ops import add gebruikt en python -m calc.cli als aanroeppad ondersteunt (lees optioneel twee getallen uit sys.argv).

Oefening 7 — Vermijd star-import Gegeven deze slechte regel: from math import *.

  • Herschrijf naar een expliciete import (kies relevante namen of gebruik import math).
  • Leg in een comment in 1 zin uit waarom * onwenselijk is.

Oefening 8 — Standaardbibliotheek mini-taken Schrijf één script met drie korte voorbeelden:

  • random.choice(["red","green","blue"]) en print het resultaat.
  • datetime.now().isoformat(timespec="seconds") en print het.
  • Controleer met pathlib.Path("notes.txt").exists() of het bestand bestaat en print een boodschap.

Oefening 9 — Derde-partij module (pip) — conceptueel Schrijf de commando’s die je zou uitvoeren in een venv om requests te installeren (niet daadwerkelijk uitvoeren hier):

  • aanmaken/activeren venv;
  • python -m pip install requests;
  • python -m pip freeze > requirements.txt. Schrijf in fetch.py voorbeeldcode die https://httpbin.org/get ophaalt met een timeout en statuscode print. Voeg een comment toe dat dit in een geactiveerde venv hoort te draaien.

Oefening 10 — Naamconflict met standaardbibliotheek Maak een bestand random.py met een eigen functie foo(). Probeer in een ander script import random; print(random.choice([1,2,3])). Observeer de fout (of het verkeerde gedrag). Hernoem jouw bestand (bijv. myrandom.py) en laat zien dat het probleem verdwijnt. Schrijf in comments de verklaring.

Uitdaging (optioneel) — Klein greet-package met CLI Maak een package greet/ met __init__.py en cli.py:

  • In __init__.py: functie hello(name: str) -> str en eventueel __all__ = ["hello"].
  • In cli.py: main() die een naam uit sys.argv leest en hello print. Toon hoe je python -m greet.cli Ava kunt gebruiken (bij juiste PYTHONPATH of na installatie in een venv).

Werkboek — Hoofdstuk 11: Basis testen en debuggen

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

  • Print‑debugging op een doelgerichte manier toepassen.
  • Aannames vastleggen met assert (ontwikkelchecks en in tests).
  • Kennismaken met unittest (standaardbibliotheek) en pytest (populair framework).
  • Foutmeldingen (tracebacks) leren lezen en focussen op eigen code.

Richtlijnen

  • Houd voorbeelden klein en gericht. Schrijf duidelijke functienamen in het Engels.
  • Gebruik assert in tests en als ontwikkelcheck; niet als gebruikersvalidatie in productiecode.
  • Voor pytest: zorg dat bestands- en functienamen met test_ beginnen.
  • Als je met floats werkt: vergelijk met tolerantie (bijv. abs(a-b) < 1e-9 of math.isclose).

Oefening 1 — Print‑debugging (gericht kijken) Er is een functie met een bug:

# normalize_name.py

def normalize_name(s: str) -> str:
    s = s.strip()
    parts = s.split()
    return "".join(part.lower() for part in parts)  # BUG: mist spaties tussen woorden
  • Schrijf een mini‑script dat de functie aanroept met " Ada Lovelace ".
  • Voeg 2–3 doelgerichte debug‑prints toe (in het script of tijdelijk in de functie) om te zien wat er misgaat.
  • Noteer (in comment) wat de bug is en hoe je die zou fixen.

Oefening 2 — Aannames met assert Schrijf een functie average(values: list[float]) -> float die het gemiddelde teruggeeft.

  • Voeg een assert len(values) > 0, "values must not be empty" toe.
  • Demonstreer in een script het succespad en het falen (lege lijst) met de resulterende AssertionError.

Oefening 3 — Kleine assert‑tests zonder framework Maak een bestand math_utils.py met functies add(a,b) en even_sum(n) (som van even getallen t/m n).

  • Schrijf een tweede bestand test_math_utils_sanity.py met 4–6 assert‑checks die deze functies controleren.
  • Run het testbestand gewoon met python en laat mislukking/succes zien.

Oefening 4 — unittest basis

  • Schrijf test_math_utils_unittest.py met een unittest.TestCase klasse met minstens twee testmethoden:
    • test_add_basic() gebruikt self.assertEqual.
    • test_even_sum_small() test enkele kleine gevallen.
  • Laat zien hoe je dit runt met python -m unittest -q (beschrijf de commandoregel in een comment).

Oefening 5 — pytest basis (installatie buiten scope hier)

  • Schrijf test_math_utils_pytest.py met twee testfuncties voor add en even_sum.
  • Voeg een test toe die een exception verwacht met pytest.raises (bijv. voor een div(a,b) die ZeroDivisionError gooit bij b==0).
  • Noteer in een comment hoe je dit zou draaien: pytest -q.

Oefening 6 — Traceback lezen Schrijf een klein script show_error.py dat bewust faalt (bijv. int("abc")).

  • Plak (in comment) een voorbeeld‑traceback en markeer welke regel jouw code was en welk exceptietype werd gegooid.
  • Schrijf 1–2 zinnen (NL) hoe je vanaf onder naar boven leest voor de kern.

Oefening 7 — Tolerantie bij floats Schrijf circle_area(r) en schrijf daarvoor tests die niet exact op decimale weergave vertrouwen.

  • Gebruik abs(actual - expected) < 1e-9 of math.isclose in je asserts.
  • Toon één case die zonder tolerantie flaky zou kunnen zijn.

Oefening 8 — Mini refactor met testnet Schrijf def slugify(text: str) -> str (zoals in eerdere hoofdstukken) en schrijf 5 asserts die gewenste gedrag vastleggen (spaties → streepjes, lowercase, alleen alfanumeriek/streepjes).

  • Introduceer bewust een bug (bijv. join zonder separator) en laat zien dat een assert faalt.
  • Fix de bug en laat alle asserts weer slagen.

Oefening 9 — unittest: exceptions en setup/teardown (licht)

  • Maak in math_utils.py een div(a,b) die ZeroDivisionError gooit bij b==0.
  • Schrijf een unittest.TestCase met setUp die een paar veelgebruikte waarden opslaat.
  • Voeg een test toe met assertRaises(ZeroDivisionError) voor div(1,0).

Oefening 10 — Korte workflow & valkuilen

  • Schrijf 3 bulletpoints (in comments) over jouw testworkflow (schrijf functie → bedenk voorbeelden → schrijf asserts → run → refactor → run).
  • Noem 3 valkuilen en de remedies (bijv. alleen “happy path” testen, asserts met floats, assert in productie i.p.v. echte validatie).

Uitdaging (optioneel) — Kleine rekenmodule met volledige cyclus Bouw calc2.py met functies add, sub, mul, div, pow en schrijf:

  • Eenvoudige pytest‑tests (of assert‑tests) die normale gevallen, randgevallen en exceptions afdekken.
  • Voeg 1–2 unittest‑tests toe als extra voorbeeld.
  • Laat zien hoe je pytest -q / python -m unittest zou gebruiken (in comments).

Hoofdstuk 12: Eindproject

- Keuzes (1 kiezen):
  - Number Guessing Game met highscore‑bestand.
  - To‑Do CLI met persistente opslag en eenvoudige tests.
  - Tekst‑gebaseerde quiz met vragenbestand (JSON/CSV).
- Eisen:
  - README met beschrijving en gebruiksvoorbeelden (Engelse code).
  - Minstens 2 modules en 5 functies.
  - Basistests (min. 5 asserts of 2 unittest‑cases).