Recent chats
ASKGEEZ Q&A GUIDETechnology & devices

When should I make a dataclass immutable?

Quick answer

Use @dataclass(frozen=True) when a record represents a value that should stay fixed after creation, such as a coordinate or measurement. It prevents assigning to or deleting fields, but does not make mutable objects stored in those fields immutable. Choose a regular dataclass when updating fields is part of the record’s intended use. Frozen dataclasses also have a small initialization performance cost. [S1]

LET’S WORK THROUGH IT

The question, the details, the next step.

Question

I have a small dataclass holding a label and a measurement. How do I decide whether to make it frozen?

Geez

Ask whether the record is meant to describe a value that stays the same, or an object that changes as your program runs. A coordinate, a measurement, or a named setting may be value-like: once created, a different value would be a different record. For that kind of record, frozen=True can make accidental field reassignment harder. A mutable dataclass is a better fit when changing a field is a normal part of the record’s job. Python’s dataclass documentation says frozen instances raise FrozenInstanceError when you assign to or delete a field, and notes a small initialization performance cost. [S1]

For example:

from dataclasses import dataclass

@dataclass(frozen=True)
class Reading:
    label: str
    value: float

@dataclass
class EditableReading:
    label: str
    value: float

With Reading, treat a changed measurement as a new record rather than editing the existing field. With EditableReading, field updates are allowed. This example assumes label and value are the only fields and that the measurement is represented by a float.

Follow-up question

Does frozen mean nothing inside the record can change?

Geez

No. It restricts reassignment or deletion of the dataclass’s fields; it does not make every object referenced by those fields immutable. [S1] For instance, a frozen record can contain a list, and the list itself may be changed. If your record contains mutable values, decide separately whether those values need to be protected, copied, or represented differently. frozen=True alone does not settle that design question.

A useful mental model is: the field binding is fixed, but a referenced object may have its own behavior. Freeze a record because its fields should not be replaced, not because you need a guarantee that all reachable data can never change.

Follow-up question

Can you show the tradeoff with a field that contains a list?

Geez

Here is a small illustrative comparison. The comments describe intended use; they are not a claim that every field value is deeply immutable.

from dataclasses import dataclass

@dataclass(frozen=True)
class FrozenTags:
    name: str
    tags: list[str]

@dataclass
class MutableTags:
    name: str
    tags: list[str]

In FrozenTags, you should not reassign name or tags after construction. But tags remains a list object, so frozen=True does not prevent changes to that list. [S1] In MutableTags, both the fields and the referenced list can be changed. If your intended record should not change at all, consider whether a list is the right representation for its contents. The documentation establishes the limitation of frozen=True, but does not prescribe a replacement for your particular application.

This distinction matters when another part of your program expects a record to remain a stable description. Decide what “unchanged” means for your fields and their contents, then choose a representation that matches.

Follow-up question

Can you give me a quick decision checklist I can use when reviewing a dataclass?

Geez

Use this short review:

  1. Is this record a value-like description that should stay fixed after creation? If yes, consider frozen=True.
  2. Should normal program behavior update its fields? If yes, use a mutable dataclass.
  3. Do any fields refer to mutable objects, such as lists? Remember that freezing the dataclass does not freeze those objects. [S1]
  4. Is the small initialization performance cost relevant in your use case? The documentation notes the cost but does not quantify it for your program. [S1]
  5. State the intended rule for callers: replace the record, edit it, or manage referenced contents separately.

A reasonable default is not “freeze every dataclass.” Choose frozen for records whose field assignments should be rejected; choose mutable when field updates are part of the design. The documentation explains field reassignment and the limitation for referenced objects, but it does not decide which policy fits your application.

A practical checklist

  • Decide whether the record represents a fixed value or an object meant to change.

  • Use frozen=True when field reassignment or deletion should be rejected.

  • Check whether fields reference mutable objects; freezing the record does not freeze their contents.

  • Consider whether the documented small initialization cost matters for your use case.

  • State whether changes should create a replacement record or update the existing one.

A few more useful answers

What happens if I assign to a field on a frozen dataclass?

The dataclass documentation says assigning to or deleting a field raises FrozenInstanceError. [S1]

Does `frozen=True` make a list field immutable?

No. It restricts changes to the dataclass’s fields, but a referenced mutable object such as a list can still be changed. [S1]

Is there any tradeoff to freezing a dataclass?

The documentation notes a small initialization performance cost. It does not quantify how significant that cost will be in a particular program. [S1]

Sources

References used for this guide.

  1. [S1] dataclasses — Data Classes (Python 3.15.2 documentation)
    docs.python.org · Checked

YOUR QUESTION. YOUR DETAILS.

Let’s work through your situation.

Get a tailored answer or help with your next task. Starts at $1, with a quote before you pay.

Ask your own question
← Back to Geez at Work