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 = []?