Vanaf Python 3.5 kan je type hints toevoegen aan je code: annotaties die aangeven wat het verwachte type is van variabelen, parameters en returnwaarden. Ze zijn optioneel โ Python controleert ze niet bij het uitvoeren โ maar ze maken code aanzienlijk leesbaarder en zijn intussen standaardpraktijk in professionele Python-projecten.
| Zonder type hints | Met type hints | |
|---|---|---|
| Bedoeling | Afgeleid uit namen en docstrings | Expliciet in de signatuur |
| IDE-ondersteuning | Beperkte autocomplete | Volledige autocomplete + waarschuwingen |
| Bugs opsporen | Pas bij uitvoer (runtime) | Al tijdens het schrijven (mypy) |
| Documentatie | Aparte docstring | Ingebouwd in de signatuur |
In ML-bibliotheken zoals NumPy, Pandas en scikit-learn zijn type hints overal aanwezig. Je zult ze ook terugvinden in het cursusmateriaal en de ondersteunende broncode.
Variabelen annoterenยถ
Je kan een variabele annoteren met : type. Dit is puur informatief โ Python negeert de annotatie, maar bibliotheken zoals mypy gaan hiermee checks uitvoeren.
age: int = 24
name: str = "Alice"
score: float = 8.5
passed: bool = True
# Annotation without assignment โ just declares the expected type
grade: float
# Python does NOT enforce type hints at runtime
age = "twenty-four" # no error โ Python just runs it
print(age)twenty-four
Functies annoterenยถ
Het meest gebruikte patroon: annoteer de parameters van een functie en de returnwaarde (na ->).
def add(x: float, y: float) -> float:
return x + y
def greet(name: str, formal: bool = False) -> str:
if formal:
return f"Good day, {name}."
return f"Hi, {name}!"
print(add(3.0, 4.5))
print(greet("Alice"))
print(greet("Dr. Smith", formal=True))7.5
Hi, Alice!
Good day, Dr. Smith.
# -> None for functions that return nothing
def log_message(message: str, level: str = "INFO") -> None:
print(f"[{level}] {message}")
log_message("Training complete")
log_message("NaN detected in input", level="WARNING")[INFO] Training complete
[WARNING] NaN detected in input
# Realistic ML example: normalize a value to [0, 1]
def normalize(value: float, min_val: float, max_val: float) -> float:
"""Scale value to [0, 1] using min-max normalization."""
return (value - min_val) / (max_val - min_val)
print(normalize(150.0, min_val=100.0, max_val=200.0)) # 0.50.5
Collectietypesยถ
Vanaf Python 3.9 kan je de ingebouwde collectietypes rechtstreeks gebruiken als type hint โ geen import nodig.
# list[element_type]
scores: list[float] = [8.5, 7.0, 9.2]
# dict[key_type, value_type]
label_counts: dict[str, int] = {"cat": 120, "dog": 95}
# set[element_type]
unique_labels: set[str] = {"cat", "dog", "bird"}
# tuple[type1, type2, ...] โ fixed-length with specific types per position
point: tuple[float, float] = (3.0, 4.0)
# tuple[type, ...] โ variable-length tuple of one type
coordinates: tuple[float, ...] = (1.0, 2.0, 3.0, 4.0)
print(scores, label_counts, point)[8.5, 7.0, 9.2] {'cat': 120, 'dog': 95} (3.0, 4.0)
def top_k(values: list[float], k: int) -> list[float]:
"""Return the k largest values in descending order."""
return sorted(values, reverse=True)[:k]
print(top_k([3.2, 8.1, 5.5, 9.0, 1.4], k=3))[9.0, 8.1, 5.5]
Optional en Unionยถ
Soms kan een waarde None zijn โ bv. een parameter die niet verplicht is of een functie die niets teruggeeft als er geen resultaat is. Gebruik de |-operator (Python 3.10+) om meerdere toegestane types te combineren.
# str | None means: a string, or None
def find_label(index: int, labels: list[str]) -> str | None:
"""Return the label at the given index, or None if out of range."""
if 0 <= index < len(labels):
return labels[index]
return None
result = find_label(2, ["cat", "dog", "bird"])
print(result) # bird
result = find_label(99, ["cat", "dog", "bird"])
print(result) # Nonebird
None
# int | float: accept either numeric type
def square(x: int | float) -> float:
return float(x**2)
print(square(3)) # int input
print(square(2.5)) # float input9.0
6.25
# Optional[str] from typing is equivalent to str | None โ older codebases use this
from typing import Optional
def get_name(user_id: int) -> Optional[str]: # same as str | None
users = {1: "Alice", 2: "Bob"}
return users.get(user_id)
print(get_name(1)) # Alice
print(get_name(99)) # NoneAlice
None
Tip: gebruik de moderne
str | None-syntax in nieuwe code. Je zultOptional[str]nog veel tegenkomen in bestaande bibliotheken.
ML-types: NumPy en Pandasยถ
In ML-code werk je voortdurend met NumPy-arrays en Pandas-structuren. Je kan die rechtstreeks als type hint gebruiken.
import numpy as np
import pandas as pd
def row_means(matrix: np.ndarray) -> np.ndarray:
"""Return the mean of each row."""
return matrix.mean(axis=1)
M = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
print(row_means(M))[2. 5.]
def drop_missing(df: pd.DataFrame) -> pd.DataFrame:
"""Return a copy of df with rows containing NaN removed."""
return df.dropna()
def get_column(df: pd.DataFrame, column: str) -> pd.Series:
"""Extract a single column as a Series."""
return df[column]
import seaborn as sns
penguins = sns.load_dataset("penguins")
clean = drop_missing(penguins)
masses = get_column(clean, "body_mass_g")
print(type(masses), masses.mean())<class 'pandas.core.series.Series'> 4207.057057057057
Type hints in klassenยถ
In klassen annoteer je instantievariabelen in de __init__-methode. Je kan ook klassevariabelen apart declareren bovenaan de klasse.
class Dataset:
name: str # class-level annotation (declared but set in __init__)
values: list[float]
def __init__(self, name: str, values: list[float]) -> None:
self.name = name
self.values = values
def mean(self) -> float:
return sum(self.values) / len(self.values)
def __repr__(self) -> str:
return f"Dataset(name={self.name!r}, n={len(self.values)})"
ds = Dataset("exam scores", [78.0, 92.0, 65.0, 88.0])
print(ds)
print("mean:", ds.mean())Dataset(name='exam scores', n=4)
mean: 80.75
Any โ het ontsnappingsluikยถ
Soms ken je het type niet op voorhand, of wil je een annotatie vermijden voor dynamische data. Daarvoor bestaat Any: het is compatibel met elk type.
from typing import Any
def log(value: Any) -> None:
"""Print any value for debugging."""
print(f"debug: {value!r} (type: {type(value).__name__})")
log(42)
log("hello")
log([1, 2, 3])debug: 42 (type: int)
debug: 'hello' (type: str)
debug: [1, 2, 3] (type: list)
Gebruik
Anyspaarzaam โ het schakelt de typechecker uit voor die waarde. Prefereer een specifiek type waar mogelijk.
Statische controle met mypyยถ
Type hints worden niet afgedwongen door Python zelf, maar een statische typechecker zoals mypy analyseert je code zonder hem uit te voeren en rapporteert type-fouten.
mypy script.pyVoorbeeld van wat mypy opspoort:
def add(x: float, y: float) -> float:
return x + y
add("hello", 3.0) # mypy error: Argument 1 has type "str"; expected "float"Dit project gebruikt mypy als onderdeel van de kwaliteitscontrole. IDEโs zoals VS Code en PyCharm tonen mypy-fouten ook inline terwijl je typt.
Oefeningenยถ
Oefening 1 โ Voeg type hints toe aan de volgende functie (parameters รฉn returntype). Welk type geeft calculate_bmi terug?
def calculate_bmi(weight_kg, height_m):
return weight_kg / height_m ** 2# your solution hereOefening 2 โ De volgende functie heeft een fout in het returntype. Identificeer de bug en herstel de annotatie.
def split_words(sentence: str) -> str:
return sentence.split()# your solution hereOefening 3 โ Schrijf een functie column_summary die een pd.DataFrame en een kolomnaam (str) accepteert en een dictionary teruggeeft met de sleutels "mean", "std", "min" en "max" (allen float). Annoteer alle types.
import pandas as pd
# your solution hereOefening 4 โ Voeg type hints toe aan deze klasse: annoteer de instantievariabelen en alle methoden.
class BoundingBox:
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
def area(self):
return self.width * self.height
def contains(self, px, py):
return self.x <= px <= self.x + self.width and self.y <= py <= self.y + self.height# your solution hereOefening 5 โ Schrijf een functie parse_int die een string probeert om te zetten naar een int. Als de conversie lukt, geef de integer terug; anders geef None terug. Annoteer het returntype correct met |.
# your solution here