Saltar a contenido

Week 8 - The Type System: Generics, Protocols, Variance, and typing.*

8.1 Conceptual Core

  • Python's type system is gradual and structural-where-it-matters. Protocol lets duck typing meet static checking - the type system catches up to the language's actual semantics.
  • Variance: list[Cat] is not a list[Animal] (mutable → invariant). Sequence[Cat] is a Sequence[Animal] (read-only → covariant). Callable[[Animal], None] accepts Callable[[Cat], None]? No (parameters are contravariant).

8.2 Mechanical Detail

  • Generics (PEP 695, 3.12+): the new clean syntax - def first[T](xs: list[T]) -> T: ... and class Box[T]: .... Old TypeVar syntax still works.
  • Protocol, runtime_checkable. Structural typing for the Iterable, Sized, SupportsLen, etc., families.
  • Literal, LiteralString (PEP 675, security-relevant), Final, NewType, TypeAlias (PEP 695: type Vector = list[float]).
  • overload: multiple stubs for one implementation. Use sparingly; usually a sign of conflated responsibilities, sometimes legitimately needed (e.g., typing.cast, JSON parser return).
  • TypeGuard (3.10) and TypeIs (3.13): user-defined narrowing predicates. TypeIs is the strictly better one going forward - it narrows in the negative branch too.
  • Annotated[T, metadata] (PEP 593): the foundation of FastAPI/Pydantic field metadata, validators, and dependency injection.

8.3 Lab - "Make Pyright Strict"

  1. Take a 500-LOC module of your existing code. Run pyright --strict. Resolve every error.
  2. Add a Protocol for a "thing-with-an-id" and refactor a function that previously took Any.
  3. Use TypeIs to narrow dict | list returned from json.loads into safe shapes for downstream use.
  4. Where you find yourself reaching for cast, document why and consider whether the boundary belongs at a Pydantic model.

8.4 Idiomatic & Linter Drill

  • Enable ruff ANN (annotation hygiene), PYI (stub files). Aim for 100% annotated public surface; private may use inference.

8.5 Production Hardening Slice

  • Add mypy --strict to CI. Generate Sphinx docs from docstrings. Publish to GitHub Pages. By end of week 8, the project has a public docs site.

Month-2 Exit Criteria

Before starting Month 3, the reader should be able to:

  1. Write a decorator that wraps both sync and async functions and preserves their type signatures under pyright --strict.
  2. Choose between dataclass, attrs, pydantic, TypedDict, and NamedTuple for a given use case and defend the choice.
  3. Add Protocols to make an old codebase amenable to dependency injection without any code change at call sites.
  4. Articulate the validation boundary in their own architecture and where the parse-don't-validate principle is or isn't held.

Comments