What are dataclasses in Python?
The @dataclass decorator auto-generates __init__, __repr__, and __eq__ for a class based on its annotated fields - less boilerplate than writing them manually.
Python
Overview
Introduced in Python 3.7, `@dataclass` eliminates the boilerplate of writing `__init__`, `__repr__`, and `__eq__` for simple data-holding classes. You declare fields with type annotations and the decorator generates the methods for you.
Key Points
- •`@dataclass` generates `__init__`, `__repr__`, and `__eq__` automatically.
- •Fields with defaults come after fields without: `x: int = 0`.
- •Use `field(default_factory=list)` for mutable defaults (never use `field: list = []`).
- •`@dataclass(frozen=True)` makes instances immutable and hashable (like a named tuple).
- •`@dataclass(order=True)` generates `<`, `<=`, `>`, `>=` comparisons.
- •For complex defaults or validation, use `__post_init__`.
Examples
Basic dataclass
pythonfrom dataclasses import dataclass
@dataclass
class Point:
x: float
y: float
label: str = '' # field with default
p1 = Point(1.0, 2.0)
p2 = Point(1.0, 2.0)
print(p1) # Point(x=1.0, y=2.0, label='')
print(p1 == p2) # True (generated __eq__)
# No need to write __init__, __repr__, or __eq__ manuallyMutable default with field()
pythonfrom dataclasses import dataclass, field
@dataclass
class Inventory:
name: str
# WRONG: items: list = [] ← shared across all instances!
items: list = field(default_factory=list)
tags: set = field(default_factory=set)
inv = Inventory('Warehouse')
inv.items.append('Box') # only this instance is affectedFrozen dataclass (immutable)
python@dataclass(frozen=True)
class Color:
r: int
g: int
b: int
red = Color(255, 0, 0)
# red.r = 128 # FrozenInstanceError: cannot assign to field 'r'
# Frozen dataclasses are hashable, so they can be dict keys or set members
palette = {red, Color(0, 255, 0)}__post_init__ for validation or computed fields
pythonfrom dataclasses import dataclass, field
@dataclass
class Rectangle:
width: float
height: float
area: float = field(init=False) # not a constructor parameter
def __post_init__(self):
if self.width <= 0 or self.height <= 0:
raise ValueError("Dimensions must be positive")
self.area = self.width * self.height
r = Rectangle(4.0, 5.0)
print(r.area) # 20.0Pro Tip
Prefer `@dataclass` over plain classes for data containers. For read-only data, use `frozen=True` - it prevents accidental mutation and makes instances hashable. For very simple tuples of values, `typing.NamedTuple` is an alternative; for full validation, look at `pydantic`.