03 — Strict Typing, Generics, Protocol & Runtime Boundaries

At a glance

After completing this lesson you can:

Time: ~45 minutes · Prerequisites: 02 — Data Model & Iterables

Reading Companion

Why this matters in production

In dynamic Python, passing a dictionary with a typo in key name (event["user_idd"]) causes a KeyError at runtime in production. With modern static typing (mypy, ruff, pyright), type errors are caught in your editor and CI before a single line runs. Furthermore, using Protocol allows you to decouple domain logic from database drivers and third-party libraries without rigid inheritance hierarchies.

Deep dive

1. Nominal vs Structural Subtyping (Protocol)

from typing import Protocol

class LogSink(Protocol):
    def emit(self, event: str) -> None: ...

Hands on

python3 phase0-foundations/03-python-internals/03-strict-typing-and-protocols/examples/01_demo.py
python3 phase0-foundations/03-python-internals/03-strict-typing-and-protocols/examples/02_trap.py

AI Trap & Code Review

# BAD AI-GENERATED CODE — OVERUSE OF Any IN INTERFACES
from typing import Any

def process_batch(items: list[Any]) -> list[Any]:
    # Disables all type checking!
    return [item.id for item in items]

Exercises

  1. Rung 1 (make_event_record): Define a frozen slots dataclass EventRecord(id: str, payload: dict[str, str], timestamp: int) and instantiate it.
  2. Rung 2 (GenericStore — Fix the AI Bug): Implement a type-safe GenericStore[T] supporting .put(key: str, item: T) and .get(key: str) -> T | None.
  3. Rung 3 (EventSender Protocol): Define a Protocol named EventSender with method send(self, topic: str, message: str) -> bool. Verify structural adherence.
  4. Rung 4 (parse_and_validate_boundary): Validate an untrusted dict into an immutable UserAccount record, raising ValueError on missing or incorrectly typed fields.
  5. Rung 5 (composite_pipeline): Build a typed pipeline function that composes generic transformations T -> U -> V.

Wrapping up

Can you explain?

  1. What is the difference between nominal subtyping (ABC) and structural subtyping (Protocol)?
  2. Why does @dataclass(slots=True) reduce memory consumption?
  3. Why does type checking pass on Any even when code crashes at runtime?

Further Reading & References

Show reference solution notes

Solution & Engineering Notes — 03 Strict Typing & Protocols

  1. Protocol vs ABC: Protocol allows third-party libraries and callers to satisfy interfaces without importing or subclassing your base class.
  2. slots=True: Removes the instance's dynamic __dict__, storing attributes in a fixed-size C array, reducing memory per instance by ~60%.

Self-check

Run python3 -m unittest phase0-foundations/03-python-internals/03-strict-typing-and-protocols/test_exercises.py -v until green, then record it here. Saved to progress/rungs.json; commit it.

Confidence:

Completion edits PROGRESS.md; commit it with the lesson.