Skip to Content

Type Hints & Dataclasses

When to use

Document expected types and bundle fields into a record class without boilerplate.

Analogy

Type hints are labels on jars (‘flour, not salt’); dataclasses are pre-printed name-tag stickers you slap on a box.

Data-flow diagram

def parse(s: str) -> list[int]:     @dataclass
    ...                              class User:
                                        name: str
# runtime: duck-typed                     age: int = 0
# mypy / pyright catch mismatches     @dataclass(frozen=True)
   before runtime                      class Id: value: int

Deep explanation

Type hints (PEP 484) live in __annotations__ and inspect.signature; they do NOT change runtime behaviour - they feed static checkers (mypy/pyright/ruff). The payoff: mismatches are caught BEFORE the code runs. @dataclass (PEP 557) auto-generates __init__, __repr__, __eq__. frozen=True makes immutable + hashable; slots=True saves memory by skipping __dict__.

Examples

Example 1

def greet(name: str, times: int = 1) -> list[str]:
    return [f'Hello {name}'] * times

annotations are doc that mypy/pyright verify.

Example 2

from dataclasses import dataclass, field
@dataclass
class Point:
    x: float
    y: float
    tags: list[str] = field(default_factory=list)

field(default_factory=list) ensures each instance gets a fresh list.

Example 3

from dataclasses import dataclass
@dataclass(frozen=True, slots=True)
class Money:
    amount_cents: int
    currency: str
# m.amount_cents = 2000  -> FrozenInstanceError

frozen=True makes hashable + immutable; slots=True saves ~50% memory.

Common mistake

Confusing types with enforcement. Hints are NOT enforced at runtime - use pydantic or beartype for untrusted input. Falling for mutable defaults (tags: list[str] = []) - every instance shares the same list.

Key takeaway

Annotate every public function; @dataclass for data records; frozen=True for value objects; slots=True for tight loops; remember hints are doc, not enforcement.

Production Failure Playbook

Failure scenario 1: mutable-default-dataclass

Failure scenario 2: no-runtime-validation-on-inbound-json