Type hints catch whole classes of bugs before running code and make editors far more helpful.
Python annotations attach types to names:
def greet(name: str, times: int = 1) -> str: ...
count: int = 0The interpreter does not enforce them. At runtime greet(42) still runs; the hints are stored in __annotations__ and otherwise ignored. Their value comes from tools:
- Static type checkers (mypy, pyright, also built into VS Code's Pylance and PyCharm) read your code and report mismatches without running it.
- Editors use hints for autocompletion and safe refactoring.
- Some libraries (FastAPI, Pydantic, dataclasses) read hints at runtime to validate or generate code.
Checkers infer most local variable types (x = 3 is an int), so annotate function signatures and class attributes, and let inference do the rest. A function with no annotations is usually treated as untyped and not checked by mypy's default settings, so start adding types at function boundaries.
Run a checker as part of your workflow: mypy src/ or pyright. Start lenient, then tighten with options like mypy's --strict as coverage grows.
reveal_type(expr) (in typing since 3.11) asks the checker to print the type it inferred; at runtime it prints the actual type.
Example
from typing import reveal_type
def area(width: float, height: float) -> float:
return width * height
total: float = area(2, 3.5) # ints are accepted where float is expected
print(total) # 7.0
print(area.__annotations__)
# {'width': <class 'float'>, 'height': <class 'float'>, 'return': <class 'float'>}
print(area("ab", 2)) # runs! prints abab
# mypy/pyright: error: Argument 1 to "area" has incompatible type "str"
reveal_type(total) # checker: float; runtime prints the actual typeRemember
- Hints describe types; Python does not enforce them at runtime
- Static checkers (mypy, pyright) verify them before code runs
- Annotate signatures; let inference handle locals
Watch out for
- Expecting a TypeError at runtime from a wrong argument type; only a checker reports it.