Inhoud
- Kennismaking
- Invoer en uitvoer
- Selecties
- Lussen en iteraties
- Lijsten
- Functies
- Foutafhandeling
- Bestanden
- Modules & venv
- Basis testen en debuggen
- 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 naarstderr. - 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, FirstFirst LastGebruik 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
ndeelbaar 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
whileen tellen/doorlopen metfor. range(start, stop, step)effectief gebruiken.- Begrijpen en toepassen van
breakencontinue. - Handige helpers gebruiken:
enumerate, iteratie over dicts, geneste lussen. - Het patroon
for-elseinzetten 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 lijstevensmet alleen de even getallen. - Bouw met een tweede
for-lus een lijstsquaresmet kwadraten van alle getallen uitnums. 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]ennums[:3]ennums[3:]. - Maak
revals 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
appendenextendrespectievelijk"green"en"blue", "green"toe. - Verwijder één keer
"green"metremove(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 vorm1. Avaetc.
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 eenkeymet een tuple, plusreverse=Truewaar nodig.
Oefening 8 — Kopiëren vs. aliasing
- Maak
original = [1, 2, 3]en zetalias = original. - Voer
alias.append(4)uit en print beide. - Maak vervolgens een échte kopie met
copy = original[:]en voeg5toe aancopy. 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] = 1en printm— 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
squaresmet de kwadraten van 0..10. - Bouw met een comprehension een lijst
evensmet de even getallen uitrange(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
setvoor 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
defen 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]) -> Nonedie 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 enbucketteruggeeft. 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 alsbucket 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) -> floatformat_line(name: str, qty: int, price: float) -> strgrand_total(items: list[tuple[str,int,float]]) -> floatrender_receipt(items: list[tuple[str,int,float]]) -> strZorg datrender_receiptgéénprintgebruikt 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
elseplaatsen en altijd‑opruimen infinallyof viawithdoen. - Fouten zelf signaleren met
raiseen, waar passend, her‑gooien met logging (re‑raise) of exception chaining gebruiken. - Eenvoudig en defensief valideren; kies tussen herstelbare en terminale fouten.
logginggebruiken i.p.v.printvoor foutmeldingen.
Richtlijnen
- Houd je
try‑blok zo klein mogelijk (alleen de riskante regels). - Vang specifieke excepties; vermijd
except:en te bredeexcept 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
floateindigen.
Oefening 3 — Calculator met ^ (macht) en nette foutmeldingen
Schrijf calc(a: float, op: str, b: float) -> float die + - * / ^ ondersteunt.
raise ZeroDivisionErrorbij deling door nul.raise ValueErrorbij 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
ConfigErrorals 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
ConfigErrormet 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 ennewline‑parameter. - Paden met
pathlib.Path: paden samenstellen, directories maken, globben. - Binaire I/O (chunks), defensief werken en veelvoorkomende valkuilen.
Richtlijnen
- Gebruik
withvoor alle bestandsoperaties. - Specificeer bij tekstbestanden
encoding="utf-8"expliciet. - Gebruik
pathlib.Pathwaar zinvol i.p.v. alleen stringpaden. - Voeg zelf
\ntoe bijwrite;print(..., file=f)voegt standaard een newline toe (tenzijendis 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) -> Nonedie JSON schrijft metensure_ascii=False, indent=2.read_config(path: Path) -> dictdie leest en het dict teruggeeft. Schrijf een__main__‑blok dat een klein config‑dict schrijft en daarna weer leest en een veld print. VangFileNotFoundErrorenjson.JSONDecodeErrormet 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.listtoont genummerde regels.done <n>markeert itemnals gedaan door het te verwijderen of te prefixen met[x](kies één en beschrijf in een comment je keuze). Gebruikwithenencoding="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
pipen virtuele omgevingen (conceptueel/uitvoering buiten dit document). - Veelvoorkomende valkuilen vermijden (naamconflicten, star-imports, verkeerde werkdirectory).
Richtlijnen
- Gebruik expliciete imports (
import packageoffrom package import name), vermijdfrom 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) -> floatf_to_c(f: float) -> floatSchrijf een apart scriptapp.pydatfrom temperature import c_to_f, f_to_cgebruikt 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 mathen gebruikmath.pi; - met
from math import pien gebruikpi. 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 exporteeradd,subvia__all__).ops.pymet functiesadd(a, b),sub(a, b),mul(a, b),div(a, b)(gooiZeroDivisionErrorbijb == 0). Schrijfmain.pydatfrom calc.ops import add, divgebruikt 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 infetch.pyvoorbeeldcode diehttps://httpbin.org/getophaalt 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: functiehello(name: str) -> stren eventueel__all__ = ["hello"]. - In
cli.py:main()die een naam uitsys.argvleest enhelloprint. Toon hoe jepython -m greet.cli Avakunt gebruiken (bij juistePYTHONPATHof 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) enpytest(populair framework). - Foutmeldingen (tracebacks) leren lezen en focussen op eigen code.
Richtlijnen
- Houd voorbeelden klein en gericht. Schrijf duidelijke functienamen in het Engels.
- Gebruik
assertin tests en als ontwikkelcheck; niet als gebruikersvalidatie in productiecode. - Voor
pytest: zorg dat bestands- en functienamen mettest_beginnen. - Als je met floats werkt: vergelijk met tolerantie (bijv.
abs(a-b) < 1e-9ofmath.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.pymet 4–6assert‑checks die deze functies controleren. - Run het testbestand gewoon met
pythonen laat mislukking/succes zien.
Oefening 4 — unittest basis
- Schrijf
test_math_utils_unittest.pymet eenunittest.TestCaseklasse met minstens twee testmethoden:test_add_basic()gebruiktself.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.pymet twee testfuncties vooraddeneven_sum. - Voeg een test toe die een exception verwacht met
pytest.raises(bijv. voor eendiv(a,b)die ZeroDivisionError gooit bijb==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-9ofmath.isclosein 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.
joinzonder 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.pyeendiv(a,b)die ZeroDivisionError gooit bijb==0. - Schrijf een
unittest.TestCasemetsetUpdie een paar veelgebruikte waarden opslaat. - Voeg een test toe met
assertRaises(ZeroDivisionError)voordiv(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 unittestzou 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).