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

Antwoorden — Hoofdstuk 6: Functies en modulair denken

Opmerking: Code is in het Engels, met korte Nederlandse toelichting erboven of eronder.

Antwoord 1 — Begroeting als functie

from typing import Final

def greet(name: str) -> str:
    return f"Hello, {name}!"

if __name__ == "__main__":
    print(greet("Ava"))
    print(greet("Bo"))

Antwoord 2 — Oppervlakte cirkel (docstring + hints)

import math

def circle_area(radius: float) -> float:
    """Return circle area given a radius.
    - Uses math.pi.
    - radius must be >= 0 (negative radii don't make physical sense).
    """
    if radius < 0:
        raise ValueError("radius must be >= 0")
    return math.pi * (radius ** 2)

if __name__ == "__main__":
    for r in (0.0, 1.5, 2.0):
        print(r, circle_area(r))

Antwoord 3 — Standaard exponent

def power(base: float, exp: int = 2) -> float:
    return base ** exp

print(power(3))            # 9 (default exp=2)
print(power(3, 3))         # 27
print(power(base=2, exp=5))# 32

Antwoord 4 — Vroege return (guard)

def safe_div(a: float, b: float) -> float | None:
    if b == 0:
        return None
    return a / b

print(safe_div(10, 2))  # 5.0
print(safe_div(3, 0))   # None

Antwoord 5 — Meerdere waarden (min, max, avg)

  • We kiezen voor raise ValueError bij lege input en documenteren dat.
from typing import Iterable, Tuple

def min_max_avg(values: list[float]) -> tuple[float, float, float]:
    """Return (min, max, avg) for non-empty list of floats.
    Raises ValueError if values is empty.
    """
    if not values:
        raise ValueError("values must not be empty")
    return min(values), max(values), sum(values) / len(values)

print(min_max_avg([3.0, 8.0, 2.0, 7.0]))

Antwoord 6 — Invoer-helper zonder print in kernfunctie

def parse_float(text: str) -> float | None:
    try:
        return float(text.strip().replace(",", "."))
    except ValueError:
        return None

if __name__ == "__main__":
    raw = input("Enter a number: ")
    value = parse_float(raw)
    if value is None:
        print("Please enter a valid number (use digits, comma or dot).")
    else:
        print(f"You entered: {value}")

Antwoord 7 — Muteren vs. kopiëren

def append_exclamation_inplace(items: list[str]) -> None:
    items.append("!")

def with_exclamation_copy(items: list[str]) -> list[str]:
    result = list(items)
    result.append("!")
    return result

if __name__ == "__main__":
    words = ["hello"]
    append_exclamation_inplace(words)
    print("after inplace:", words)         # mutated
    words2 = ["hello"]
    out = with_exclamation_copy(words2)
    print("original:", words2)              # unchanged
    print("returned:", out)

Antwoord 8 — Scope (LEGB) demonstratie

x = 10  # global

def demo() -> None:
    x = 5  # local shadows global x inside this function
    print("inside demo:", x)

if __name__ == "__main__":
    demo()
    print("outside:", x)
    # Opmerking: binnen demo() zien we de lokale x=5; buiten blijft x=10.

Antwoord 9 — Docstring en help

def slugify(text: str) -> str:
    """Convert text to a lowercase, dash-separated slug.

    Example:
        >>> slugify("Hello World!")
        'hello-world'
    """
    return "-".join(
        "".join(ch.lower() for ch in text if ch.isalnum() or ch.isspace()).split()
    )

if __name__ == "__main__":
    print(slugify.__doc__)
    help(slugify)  # rendering depends on environment
    print(slugify("Hello World!"))

Antwoord 10 — Mutabel standaardargument (slecht vs. goed)

# BAD: default list is created once and reused across calls

def add_item_bad(item, bucket=[]):
    bucket.append(item)
    return bucket

print(add_item_bad(1))  # [1]
print(add_item_bad(2))  # [1, 2]  <-- unexpected accumulation across calls

# GOOD: use None sentinel and create a new list inside

def add_item(item, bucket=None):
    if bucket is None:
        bucket = []
    bucket.append(item)
    return bucket

print(add_item(1))  # [1]
print(add_item(2))  # [2]  -- independent default per call

Uitdaging (optioneel) — Refactor naar functies

from typing import Iterable

def line_total(qty: int, price: float) -> float:
    return qty * price

def format_line(name: str, qty: int, price: float) -> str:
    total = line_total(qty, price)
    return f"{name:<12}{qty:>4}{price:>9.2f}{total:>9.2f}"

def grand_total(items: list[tuple[str, int, float]]) -> float:
    return sum(line_total(q, p) for _, q, p in items)

def render_receipt(items: list[tuple[str, int, float]]) -> str:
    lines = [f"{'Item':<12}{'Qty':>4}{'Price':>9}{'Total':>9}"]
    for name, qty, price in items:
        lines.append(format_line(name, qty, price))
    lines.append(f"{'Grand total:':<25}{grand_total(items):>9.2f}")
    return "\n".join(lines)

if __name__ == "__main__":
    items = [("apple", 3, 0.60), ("banana", 2, 0.50), ("cherry", 10, 0.20)]
    print(render_receipt(items))