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