Type hints document intent, power editor autocompletion and catch bugs before runtime in large codebases.
Type hints annotate what types a function expects and returns: def greet(name: str, times: int = 1) -> str:. Python itself ignores them at runtime — they are metadata. Their value comes from tools: a static type checker such as mypy or pyright, and editors that use them for completion and error highlighting.
The essentials for modern Python (3.10+ syntax):
- built-in generics:
list[int],dict[str, float],tuple[int, str],tuple[int, ...],set[str] - unions with
|:int | str; optional values asstr | None collections.abctypes for parameters: acceptIterable[str]orSequence[int]orMapping[str, int]rather thanlist/dict, so callers can pass any suitable objecttyping.Anyopts out of checking;objectmeans "anything, but I won't assume its methods"Callable[[int, str], bool]for functions
Annotate variables when the type isn't obvious: cache: dict[str, bytes] = {}. Annotating every local isn't necessary; checkers infer types from assignments.
Be liberal in what you accept and specific in what you return: take Iterable[str], return list[str].
For your own code, start by annotating public function signatures and run the checker in CI. reveal_type(x) (in typing since 3.11) makes the checker print what it infers, which is a great way to learn. Since annotations aren't enforced, use explicit validation for untrusted data such as user input or JSON.
Example
from collections.abc import Iterable, Callable
def average(values: Iterable[float]) -> float:
items = list(values)
return sum(items) / len(items) if items else 0.0
def find_user(users: dict[int, str], user_id: int) -> str | None:
return users.get(user_id)
def apply(fn: Callable[[int], int], data: list[int]) -> list[int]:
return [fn(x) for x in data]
print(average([1.0, 2.5, 4.0])) # 2.5
print(average(x / 2 for x in range(5))) # 1.0
name = find_user({1: "ana"}, 2)
if name is not None: # narrows str | None to str
print(name.upper())
print(apply(lambda x: x * 10, [1, 2])) # [10, 20]
print(average.__annotations__) # hints are just metadata
print(find_user({1: "ana"}, "1")) # None -- not checked at runtimeRemember
- Hints are ignored at runtime; a checker like mypy/pyright enforces them
- Use
list[int],X | None, andcollections.abctypes - Accept abstract types (Iterable), return concrete ones (list)
Watch out for
- Believing a hint like
x: intmakes Python reject a string at runtime.