Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Immutable fields

Project overview and reading path

Several components share feature configuration. One component must not silently change the features seen by another.

Typical Python

from dataclasses import dataclass


@dataclass(frozen=True)
class Config:
    features: list[str]


config = Config(["height", "width"])
config.features.append("area")

Freezing the record blocks field reassignment but permits mutation of the list. The append succeeds and changes shared state.

Alternative

@dataclass(frozen=True)
class Experiment:
    seed: int
    features: tuple[str, ...]


config = Experiment(seed=17, features=("height", "width"))
expanded_features = config.features + ("area",)

Source

The tuple field has no .append, so that operation is rejected as missing-attribute. Frozen fields reject reassignment, and Final protects the default binding in checked code. The caller’s expanded_features is a new tuple; config.features still contains only ("height", "width").

Immutability is shallow. A frozen record containing a mutable array still exposes that array’s mutation. Here each feature name is a string, so a tuple fits the actual contract. Environment parsing is a separate boundary.