Python Type Hints
Annotate code with static types for tooling, clarity, and safer refactors
Overview
Type hints annotate variables, parameters, and return values so tools like mypy and Pyright can catch bugs before runtime. They are not enforced by the interpreter—Python stays dynamically typed—but they document intent and power editor autocomplete. Modern syntax (Python 3.10+) supports built-in generics and the X | Y union operator.
Syntax / Usage
Annotate with a colon for values and an arrow for return types. Use typing for generics, optionals, and callables.
from typing import Optional, Callable
def greet(name: str, times: int = 1) -> str:
return f"Hi {name}! " * times
count: int = 0
names: list[str] = ["ada", "linus"]
scores: dict[str, float] = {"ada": 9.5}
# Optional[T] is shorthand for T | None
def find(users: list[str], target: str) -> Optional[int]:
return users.index(target) if target in users else None
# Callable[[arg types], return type]
transform: Callable[[int], int] = lambda x: x * 2
Run a static checker with mypy your_module.py; the interpreter ignores the hints at runtime.
Examples
Generic function preserving the input type with a TypeVar:
from typing import TypeVar
T = TypeVar("T")
def first(items: list[T]) -> T:
return items[0]
reveal_x = first([1, 2, 3]) # inferred as int
reveal_y = first(["a", "b"]) # inferred as str
A Protocol for structural typing—any object with the right shape matches:
from typing import Protocol
class Sized(Protocol):
def __len__(self) -> int: ...
def describe(obj: Sized) -> str:
return f"length is {len(obj)}"
describe([1, 2, 3]) # lists satisfy Sized
describe("hello") # so do strings
Common Mistakes
- Believing hints are enforced at runtime; they are ignored unless a checker runs
- Using bare
listordictinstead of parameterizedlist[str], losing element type info - Reaching for
Anytoo often, which silently disables checking for that value - Forgetting
Optional(or| None) when a value can beNone, causing "possibly None" errors - Writing circular imports for type-only references instead of using
from __future__ import annotations
See Also
python-dataclasses python-functions python-classes