Python types have an expectations problem

Python’s type hints are drawing scrutiny for creating an “expectations mismatch”: they look like a built‑in type system, but provide no guarantees unless you add external tools such as mypy or pyright and wire them into your editor, CI, or deployment pipeline. Commenters debate whether Python should offer stricter, opt‑in enforcement similar to TypeScript or Rust, share practical strategies and pain points when gradually typing large legacy codebases, and point to libraries like Pydantic or Sorbet‑style runtime checks as partial solutions. Opinions diverge on the broader value of static typing in a dynamic language, with some citing improved tooling, refactoring safety, and earlier bug detection, and others arguing it adds verbosity without clear evidence of fewer defects.

Expectation Mismatch: Type Hints vs Enforcement

  • Many see a mismatch: type hints are in the standard library and syntax, but CPython ignores them at runtime and no checker runs by default.
  • Some argue Python was never going to ship a full type checker; external tools (mypy, pyright) are the practical solution, analogous to TypeScript compilers.
  • Others would like a “strict” or wrapper mode that runs a type checker before execution, especially for deployments (e.g., fail-fast on Kubernetes startup instead of at runtime).

Versioning, Errors, and Tooling

  • Newer typing syntax (e.g., dict[int, int]) on older Python produces confusing runtime errors (“type object is not subscriptable”).
  • from __future__ import annotations doesn’t fully solve this; there are edge-case bugs and obscure behavior.
  • IDEs (VS Code, PyCharm) generally use type hints for completion, though coverage is incomplete and often relies on stub packages.

Gradual Typing Legacy Codebases

  • Adopting typing in large, untyped codebases is reported as painful:
    • Running mypy on the whole repo yields unmanageable error floods, so CI checks are often ignored.
    • “Seed file” approaches (manually listing files to type-check) add friction and CI churn.
  • Suggested strategies: use mypy’s per-module config, disable import-following initially, type leaf modules first, and ratchet strictness over time.
  • Pre-commit mypy hooks are seen as too slow and disruptive; CI-only is preferred.

Expressiveness and Runtime Use

  • Python can model complex behaviors: unions, overloads, TypeVars, and recursive types, but often with verbose patterns (@overload, large stub sets) and practical limits.
  • Some use annotations at runtime (e.g., Pydantic, custom JSON/dataclass loaders, strict-typing libraries), but this is slower and not officially the design goal.

Typing vs Productivity Debate

  • One camp claims static typing in Python adds boilerplate, lengthens development, and may increase bugs per feature; they argue most bugs are behavioral and require tests anyway, and that Python’s typing isn’t strong enough for huge monoliths.
  • Others strongly dispute this, citing large typed Python codebases where annotations improved comprehension, IDE support, refactors, and caught real bugs early.
  • Empirical claims about bug rates and effectiveness of typing are contested; no clear consensus or definitive evidence is presented in the thread.

Documentation vs Inline Annotations

  • Some prefer rich docstrings (or comment-based hints) over inline type syntax for readability, wanting “pure code” with types as secondary metadata.
  • Others argue best practice is to use both: inline hints for tools and quick understanding, plus docstrings for higher-level semantics.