0%

Dataclasses and Value Objects · practice

Freeze Value Objects

Chapter 7 made hash inputs read-only with properties. A dataclass can express the same decision directly.

Freeze a value

Try it

is refused:

points.amount = 5

The amount attribute cannot be reassigned. It holds an integer, so the used by equality stays stable and the generated hash is safe:

Try it

Why is the generated hash safe for this frozen Points class?

Entities make a different promise

An attempt exists in order to change. Keep it . It also represents one event, so two matching attempts must retain identity equality:

@dataclass(eq=False)
class QuizAttempt:
    learner: str
    responses: list = field(default_factory=list)

eq=False turns off generated value equality. Ordinary identity equality and identity hashing remain.

ValueEntity
ExamplePoints, QuestionQuizAttempt
EqualityContentsIdentity
FrozenUsuallyUsually not
HashContents, when fields support itIdentity

Frozen is shallow: it prevents assigning an attribute, but a mutable stored inside can still change. A genuinely immutable value should itself contain immutable values.

The exercise classifies three values and one entity. Making new versions of frozen values is the next lesson’s single subject.

Task

Freeze what should be frozen and preserve entity identity.

Make Points, Duration, and Question frozen dataclasses. They should refuse and work in sets or as .

Keep their construction rules in __post_init__: points are positive; duration minutes are non-negative and seconds are from 0 through 59; a question has a non-empty prompt and answer and positive points.

Leave QuizAttempt changeable and use eq=False so distinct attempts compare by identity. Its responses must remain independent per attempt.