跪拜 Guibai
← All articles
Python

How Type Hints and mypy Bring Compile-Time Checks to Python

By vipxieliang ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Python's dynamic typing moves type errors from runtime to edit time when combined with type hints and mypy, cutting debugging costs and making large codebases more maintainable. The staged adoption plan makes this feasible for codebases already running in production, without a full rewrite.

Summary

Python's dynamic typing defers type errors to runtime. Type hints, introduced in PEP 484, declare types in source without affecting runtime. Running mypy catches incompatible arguments, missing None checks, and return-type mismatches during development. The syntax ranges from simple variable annotations to generics: built-in generics like list[str] and dict[str, int] work from Python 3.9, and the | operator shortens Optional and Union from 3.10. For classes, dataclasses pair naturally with annotations, and TypeVar preserves type information through generic functions and classes, with PEP 695 simplifying the syntax in 3.12.

Adopting mypy on an existing codebase follows a staged path: check only new code, exempt old modules with # type: ignore, enable strict per module, then wire mypy into CI. Configuration lives in pyproject.toml with options like disallow_untyped_defs and warn_return_any. Three recurring problems get concrete fixes: third-party libraries missing stubs (install types-requests or add ignore_missing_imports), circular imports (use from __future__ import annotations or string forward references), and dynamic attributes (prefer TypedDict or Protocol).

Takeaways
— Type hints don't affect runtime behavior, but mypy checks them at edit time, surfacing type mismatches before code ships.
— Python 3.9+ supports built-in generics like list[str] and dict[str, int]; Python 3.10+ supports the | syntax for Optional and Union.
— Optional[T] is shorthand for T | None, and mypy forces explicit None checks before attribute access on optional values.
— TypeVar preserves type information in generic functions and classes; Python 3.12 simplifies generic class syntax with PEP 695.
— mypy configuration options include disallow_untyped_defs, no_implicit_optional, warn_return_any, and a strict mode.
— The gradual adoption strategy runs in four stages: check new code, exempt old code, enable strict per module, then add mypy to CI.
— Circular imports are fixed with from __future__ import annotations or string forward references.
— Third-party libraries without stubs can be handled with ignore_missing_imports overrides or stub packages like types-requests.
— Avoid the mutable default trap by using None as a default and initializing inside the function body.
— Class-level types return their own type with Self in Python 3.11+ or string forward references in older versions.
Conclusions

Type hints convert function signatures into machine-checked documentation; the initial cost of writing them repays itself during refactoring and onboarding.

The guide's pragmatic warning about Any is important: one Any can silently disable type checking for an entire downstream call chain, so its use needs discipline.

The staged adoption plan acknowledges that strict mode from day one would overwhelm most teams, so it prioritizes incremental progress over immediate perfection.

The emphasis on IDE integration (PyCharm, Pylance) suggests that the real value of type hints often appears through editor tooling, not just mypy reports.

Concepts & terms
TypeVar
A generic type variable used in function and class signatures to preserve type information across calls. For example, def first(items: list[T]) -> T keeps the element type intact.
PEP 695
Python 3.12 syntax for generics that lets you write class Stack[T] directly, replacing the older TypeVar and Generic boilerplate.
Optional and Union
Optional[T] means T or None; Union[A, B] means either A or B. In Python 3.10+, the | operator offers shorter syntax, e.g., str | None.
mypy
A static type checker for Python that reads type hints and reports mismatches at development time without executing the code.
Callable
A type hint for function objects, written as Callable[[param_type, ...], return_type], used to annotate function parameters or higher-order functions.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗