PEP 557 in 90 seconds — @dataclass and the death of 50-line __init__
Annotations in, real class out. No boilerplate.
Before `@dataclass`, writing a simple data class was a litany of boilerplate: ```python class Point: def __init__(self, x, y=0): self.x = x self.y = y def __repr__(self): return f"Point(x={self.x}, y={self.y})" def __eq__(self, other): return isinstance(other, Point) and self.x == other.x and self.y == other.y ``` That's six lines saying "x is x, y is y". PEP 557 (Python 3.7, 2017) shipped `@dataclass` — write the annotations once, the decorator synthesises the rest.
`@dataclass` reads your class's annotations and generates `__init__`, `__repr__`, and `__eq__` automatically. For mutable defaults (lists, dicts), you use `field(default_factory=...)` so the default isn't shared across instances — the same trap as a mutable default argument. Extras: `frozen=True` makes instances immutable (`__hash__` synthesised too); `kw_only=True` (3.10+) forces keyword-only args; `slots=True` (3.10+) gives you `__slots__` for memory wins. PEP 681 generalises the whole pattern so Pydantic + SQLAlchemy v2 can opt in without inheriting from dataclass itself.
class Cart:
def __init__(self, user_id, items=None, discount=0.0):
self.user_id = user_id
self.items = items if items is not None else [] # mutable-default trap
self.discount = discount
def __repr__(self):
return f"Cart(user_id={self.user_id}, items={self.items}, discount={self.discount})"
def __eq__(self, other):
if not isinstance(other, Cart):
return NotImplemented
return (self.user_id, self.items, self.discount) == (other.user_id, other.items, other.discount)from dataclasses import dataclass, field
@dataclass
class Cart:
user_id: int
items: list = field(default_factory=list) # safe mutable default
discount: float = 0.0
# Synthesised methods: __init__, __repr__, __eq__.
# field(default_factory=list) avoids the shared-default trap.
# Optional: @dataclass(frozen=True) for immutability + __hash__.
# Optional: @dataclass(slots=True) on 3.10+ for __slots__ memory wins.🎯 Predict the output
What does this print? `@dataclass` generates `__init__`, `__repr__`, and `__eq__` from the field annotations.
from dataclasses import dataclass, field
@dataclass
class Cart:
user_id: int
items: list = field(default_factory=list)
discount: float = 0.0
c = Cart(user_id=42)
c.items.append("apple")
c.items.append("banana")
print(c)
print(c == Cart(user_id=42, items=["apple", "banana"]))