Immutable values are safe to share, cache and use as dict keys or set members.
@dataclass(frozen=True) makes instances read-only after __init__: assigning or deleting an attribute raises dataclasses.FrozenInstanceError (a subclass of AttributeError).
Benefits:
- Instances can't be changed behind your back when shared between functions or threads.
- With
eq=True(the default) andfrozen=True, a__hash__is generated from the fields, so instances work as dict keys and set members. - They signal intent: this is a value, like a date or a coordinate.
To "change" a frozen instance, make a new one: dataclasses.replace(obj, field=new_value) copies all fields and overrides the given ones. Python 3.13 also adds the generic copy.replace(obj, ...), which works for dataclasses, named tuples and other supporting types.
Two caveats:
- Frozen is shallow: a
listfield can still be mutated in place. Use tuples orfrozensetfor truly immutable data. - Inside
__post_init__, normal assignment is blocked too. To set a derived field there, useobject.__setattr__(self, "name", value), the documented escape hatch.
Frozen instances are slightly slower to create, since __init__ uses object.__setattr__.
Example
import copy
from dataclasses import dataclass, replace, FrozenInstanceError
@dataclass(frozen=True)
class Money:
amount: int
currency: str = "EUR"
price = Money(500)
try:
price.amount = 600
except FrozenInstanceError as e:
print("blocked:", e) # blocked: cannot assign to field 'amount'
discounted = replace(price, amount=450)
print(price, discounted) # Money(amount=500, currency='EUR') Money(amount=450, currency='EUR')
print(copy.replace(price, currency="USD")) # Money(amount=500, currency='USD') (3.13)
totals = {Money(500): "five euros"} # hashable: usable as a dict key
print(totals[Money(500)]) # five eurosRemember
- frozen=True blocks attribute assignment after __init__
- Frozen + eq makes instances hashable
- replace() and copy.replace() (3.13) create modified copies
Watch out for
- Assuming frozen means deeply immutable; list fields can still be changed in place.