Dataclasses — Boilerplate-Free Data Objects
Intermediate@dataclass auto-generates __init__, __repr__ and __eq__ from type-annotated fields — with defaults, immutability (frozen=True), ordering, and field factories for mutables.
Overview
Half of OOP code is classes that just hold data — and writing __init__/__repr__/__eq__ for each is pure boilerplate. @dataclass (Python 3.7+) generates them from the field declarations. Add frozen=True for immutable, hashable value objects; order=True for sortable ones; field(default_factory=list) for safe mutable defaults (the mutable-default trap returns here, and dataclasses force you to handle it correctly). This is Java records / Lombok, built into the language.
From 15 Lines to 5
Annotate fields with types; defaults follow non-defaults. You get construction, comparison and display for free — and __post_init__ for validation.
from dataclasses import dataclass, field
@dataclass
class Student:
name: str
roll: int
cgpa: float = 0.0
skills: list[str] = field(default_factory=list) # SAFE mutable default
def __post_init__(self): # validation hook
if not 0 <= self.cgpa <= 10:
raise ValueError("cgpa out of range")
s1 = Student("Asha", 41, 8.7, ["python"])
s2 = Student("Asha", 41, 8.7, ["python"])
print(s1) # Student(name='Asha', roll=41, cgpa=8.7, skills=['python'])
print(s1 == s2) # True — field-wise __eq__ generated
# skills=[] as a plain default would raise:
# ValueError: mutable default <class 'list'> ... use default_factoryfrozen, order & asdict
frozen=True makes instances immutable AND hashable (usable in sets/dict keys). order=True generates < <= > >= from field order. asdict() converts to a plain dict — handy for JSON.
from dataclasses import dataclass, asdict
@dataclass(frozen=True, order=True)
class Version:
major: int
minor: int
patch: int = 0
v1 = Version(1, 9)
v2 = Version(2, 0)
print(v1 < v2) # True — compares (1,9,0) < (2,0,0)
print(sorted([v2, v1])) # [Version(1,9,0), Version(2,0,0)]
releases = {v1, v2} # hashable because frozen
# v1.major = 3 # FrozenInstanceError
print(asdict(v2)) # {'major': 2, 'minor': 0, 'patch': 0}
# When NOT to use dataclasses: behaviour-heavy classes with little data,
# or validation-heavy API models — that's Pydantic's job (later chapter).Key Points to Remember
- 1@dataclass generates __init__, __repr__, __eq__ from annotated fields
- 2Mutable defaults MUST use field(default_factory=list) — enforced at class creation
- 3frozen=True → immutable + hashable; order=True → sortable by field order
- 4__post_init__ is the validation hook; asdict()/astuple() for serialization
Interview Questions
Sign in to ask AriaWhat does @dataclass generate for you? How do defaults for mutable fields work?
How do you make a dataclass usable as a dict key?
Dataclass vs namedtuple vs Pydantic model — when each?
Ask Aria about Dataclasses — Boilerplate-Free Data Objects
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.