Dataclasses reduce boilerplate but do not automatically guarantee deep immutability. Mutable fields need appropriate construction and ownership.
Before you start
You should know Python functions, collections and exceptions. Use a small isolated script or interactive session to trace the example. Pay attention to when objects are created and when work executes; iteration, binding and mutation can happen at different points in a program.
The practical goal is to reason through this situation: Use default_factory for a new list per instance. Read the walkthrough first, then try the interview exercise before opening its answer. The important part is explaining the decision and its consequences, rather than remembering a definition alone.
Step-by-step walkthrough
Step 1: Give instances independent fields
Use default_factory for mutable values created per instance.
Step 2: Inspect frozen reachability
Frozen fields prevent normal reassignment, not mutation inside a referenced list.
Step 3: Choose immutable storage
Use tuples of immutable elements when the value should remain stable.
Worked scenario
Use default_factory for a new list per instance.
from dataclasses import dataclass, field
@dataclass
class Draft:
tags: list[str] = field(default_factory=list)
a, b = Draft(), Draft()
a.tags.append('python')
print(b.tags) # []A and B own different lists. Changing the class to frozen does not make a.tags recursively immutable.
Common mistake
A frozen dataclass can still reference a mutable list.
Verify the behavior
Compare two instances and attempt nested mutation in a frozen variant.
Interview exercise
Model an immutable collection field.
Answer and reasoning
Store immutable elements in a tuple or make defensive copies and document any remaining shared references.
Continue learning
Compare the scenario with the Python interview questions and test your understanding with the Python MCQs. For terminology and implementation details, consult the reference material.