Typing
12 min
Type hints annotate what a function expects and returns — they make code easier to read and let editors/tools catch mistakes before you run anything.
def add(a: int, b: int) -> int:
return a + b
a: int says "a is expected to be an int," -> int says "this returns an
int." None of that changes what the function actually does at runtime —
Python still runs add("2", "3") and returns "23" without complaint.
Optional[str] means 'a str, or None' — shorthand for Union[str, None]. It documents that callers need to handle the None case.
Type hints are checked by a separate static type checker (like mypy or Pyright), not by the Python interpreter itself. That's why they're sometimes called "gradual typing" — you can add them incrementally to an existing codebase without breaking anything, and the interpreter simply ignores them at runtime. The benefit comes from tooling: your editor can warn you immediately if you pass the wrong type, and a type checker can catch bugs in CI before they ever run.
Common generic hints you'll see constantly: list[int], dict[str, int],
Optional[X] (X or None), Union[X, Y] (X or Y).
Write a function `safe_get(d: dict, key: str, default=None)` with type hints on `d` and `key`, that returns `d[key]` if `key` is in `d`, otherwise `default`.
Using the `Optional`/`List` imports below, write `first_or_none(items: List[int]) -> Optional[int]` that returns the first element of `items`, or None if `items` is empty.
Do Python type hints get enforced by the interpreter at runtime?
You can annotate function signatures with type hints and know they're a tooling aid, not a runtime enforcement mechanism.