Dataclass mutable defaults
The gotcha
Same root issue as 01_mutable_default_arguments.md, but specific to @dataclass: trying to use field: list = [] raises a ValueError at class construction time. You must use field(default_factory=list).
Minimal repro
from dataclasses import dataclass
@dataclass
class Bad:
items: list = []
# ValueError: mutable default <class 'list'> for field items is not allowed:
# use default_factory
The error message is helpful — Python catches the bug at class-definition time for dataclasses. Without dataclass:
class Bad:
items = [] # silent bug — class variable shared by all instances
a = Bad(); b = Bad()
a.items.append(1)
b.items # [1] ← shared
Why it happens
@dataclass validates field defaults. Mutable types (list, dict, set) raise immediately because the framework knows you almost certainly meant “fresh value per instance”. Non-mutable defaults (int, str, None, frozen dataclasses) are fine.
default_factory is a callable invoked once per __init__ call:
from dataclasses import dataclass, field
@dataclass
class Good:
items: list = field(default_factory=list)
metadata: dict = field(default_factory=dict)
tags: set = field(default_factory=set)
Subtler variants
Frozen dataclass with mutable nested values
@dataclass(frozen=True)
class Config:
options: list = field(default_factory=list)
c = Config()
c.options.append("x") # works — frozen blocks attribute *rebinding*, not mutation
c.options = [] # FrozenInstanceError
frozen=True prevents setting attributes, but doesn’t make their values immutable. Use tuple or frozenset if you want true immutability.
Sentinel default
If “no value” is meaningful and None is a valid value, use dataclasses.MISSING sentinel or a custom one:
_UNSET = object()
@dataclass
class Settings:
timeout: object = field(default=_UNSET)
Interview angle
“What’s wrong with @dataclass\nclass C:\n items: list = []?” Then: “How would you fix it?” — field(default_factory=list) is the answer.