2.1.1 Type Hints Basics
Python stays dynamically typed at runtime. Type hints are extra annotations that tools (and readers) use to see what a function expects and returns. The interpreter does not enforce them unless you add a checker such as mypy or your editor’s language server.
def area(width: float, height: float) -> float:
return width * height
width: float documents the parameter. -> float documents the return value.
Built-in collection types
Modern Python lets you parameterize built-in collections:
def titles(rows: list[dict[str, str]]) -> list[str]:
return [row["title"] for row in rows]
Useful forms:
list[int],set[str],tuple[int, int]dict[str, float]int | Nonewhen a value may be missing (older spelling:Optional[int])
def find_user(users: dict[int, str], user_id: int) -> str | None:
return users.get(user_id)
Why hints help
- Editors complete methods that exist on that type.
- Checkers catch
Noneused as a string, or a list passed where a dict is required. - Readers see the contract without guessing from the body.
Hints are most valuable at boundaries: public functions, class attributes, and data you load from JSON or a database.
Gradual typing
You do not have to annotate everything. Start with new modules and public APIs. A function with no hints is still valid Python.
from typing import TypedDict
class Particle(TypedDict):
x: float
y: float
mass: float
def kinetic_energy(p: Particle, speed: float) -> float:
return 0.5 * p["mass"] * speed * speed
TypedDict describes a dictionary that always has those keys. It is a hint only; at runtime it is still a dict.
What hints are not
They are not runtime validation. area("3", "4") still runs unless you check types yourself or use a library that reads annotations. Treat hints as a contract for humans and tools, then test the values you do not trust.