🎓 A1Learner
🔍

Python Dataclass Fields

field() is a function that fine-tunes one dataclass field.

A bare list default is refused

Python stops this class as soon as it is defined. One shared list would mix the members of every team.

from dataclasses import dataclass, field

@dataclass
class Team:
    name: str
    members: list = []

default_factory builds a fresh list

A factory is a function Python calls for a fresh value. Each Team now gets its own empty list.

from dataclasses import dataclass, field

@dataclass
class Team:
    name: str
    members: list = field(default_factory=list)

reds = Team("Reds")
blues = Team("Blues")
reds.members.append("Ana")
print(reds.members)
print(blues.members)

compare=False leaves a field out of equality

The score is still stored on each player. Equality simply ignores it.

from dataclasses import dataclass, field

@dataclass
class Player:
    name: str
    score: int = field(compare=False)

print(Player("Ana", 10) == Player("Ana", 99))

repr=False hides a field from display

The code stays stored on the player. It just stays out of the printed form.

from dataclasses import dataclass, field

@dataclass
class Player:
    name: str
    code: int = field(default=0, repr=False)

ana = Player("Ana", 1234)
print(ana)
print(ana.code)

frozen=True locks the fields

A frozen dataclass refuses new field values after creation. Because nothing can change, its objects can be hashed.

from dataclasses import dataclass

@dataclass(frozen=True)
class Point:
    x: int
    y: int

point = Point(2, 3)
print(point)
print(hash(point) == hash(Point(2, 3)))

Changing a frozen field fails

The assignment raises an error instead of changing the point.

point = Point(2, 3)
point.x = 5

__post_init__ checks the values

Python runs __post_init__ right after the generated __init__. Put your checks there, in one place.

from dataclasses import dataclass

@dataclass
class Team:
    name: str

    def __post_init__(self):
        if not self.name.strip():
            raise ValueError("Team name must not be empty")

print(Team("Reds").name)

Bad values stop at the door

A name of only spaces fails the strip check. The object is never handed to your code.

Team("   ")

Example

from dataclasses import dataclass, field

@dataclass(frozen=True)
class Point:
    x: int
    y: int

@dataclass
class Team:
    name: str
    home: Point
    members: list = field(default_factory=list)

    def __post_init__(self):
        if not self.name.strip():
            raise ValueError("Team name must not be empty")

reds = Team("Reds", Point(2, 3))
reds.members.append("Ana")
blues = Team("Blues", Point(5, 1))
print(reds)
print(blues.members)
print(reds.home)
print(hash(Point(2, 3)) == hash(reds.home))

Key points

  • field(): a function that fine-tunes one dataclass field
  • Use field(default_factory=list) when every object needs its own list
  • Use compare=False to leave a field out of equality checks
  • Use repr=False to leave a field out of the printed form
  • Frozen dataclass: a dataclass whose fields cannot change after creation
  • __post_init__: runs right after the generated __init__ finishes

In this example, Point is a frozen dataclass with two fields. Team stores a name, a home Point, and a members list. field(default_factory=list) builds a fresh list for every team. __post_init__ rejects a name that is empty or only spaces. Both team names pass the check, so both objects are created. Ana joins reds only, and blues keeps its own empty list. The frozen home Point hashes like any equal Point.

Note

frozen=True blocks new values for the fields themselves.

It does not freeze a list stored inside a field.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Python Playground

Exercise

Why does a dataclass refuse the default members: list = []?