Python Dataclasses
Generate boilerplate-free classes for structured data with the dataclass decorator
Overview
The @dataclass decorator auto-generates __init__, __repr__, and __eq__ from annotated class fields, eliminating repetitive boilerplate. It is ideal for plain data containers where you would otherwise write tedious constructors. Options like frozen, order, and field give fine control over immutability, comparison, and defaults.
Syntax / Usage
Decorate a class and declare fields with type annotations. The decorator wires up the dunder methods.
from dataclasses import dataclass, field
@dataclass
class Point:
x: float
y: float
label: str = "origin" # field with a default
@dataclass(frozen=True, order=True)
class Version:
major: int
minor: int
tags: list[str] = field(default_factory=list) # mutable default
p = Point(1.0, 2.0)
print(p) # Point(x=1.0, y=2.0, label='origin')
print(p == Point(1.0, 2.0)) # True
Use field(default_factory=...) for mutable defaults; a bare [] default would be shared across instances.
Examples
An immutable, sortable record. frozen=True makes instances hashable and read-only:
from dataclasses import dataclass
@dataclass(frozen=True, order=True)
class Employee:
salary: int
name: str
team = [Employee(90_000, "ada"), Employee(120_000, "linus")]
print(sorted(team)[0].name) # 'ada' — sorted by salary first
Post-init validation and derived fields with __post_init__:
from dataclasses import dataclass, field
@dataclass
class Rectangle:
width: float
height: float
area: float = field(init=False)
def __post_init__(self) -> None:
if self.width <= 0 or self.height <= 0:
raise ValueError("dimensions must be positive")
self.area = self.width * self.height
print(Rectangle(3, 4).area) # 12
Common Mistakes
- Using a mutable default like
field: list = [], which raises aValueError—usedefault_factory - Placing fields with defaults before fields without them, causing a
TypeError - Expecting
frozen=Trueinstances to be mutable; assignment raisesFrozenInstanceError - Adding heavy behavior to dataclasses when a regular class better expresses the intent
- Forgetting that
eq=Falsealso disables hashing behavior you might rely on
See Also
python-type-hints python-classes python-iterators-protocol