datarekha
Python Easy Asked at GoogleAsked at MetaAsked at AmazonAsked at StripeAsked at Airbnb

What does `@dataclass` give you over a plain class, and what are its main configuration options?

The short answer

`@dataclass` auto-generates `__init__`, `__repr__`, and `__eq__` from the field annotations declared in the class body, eliminating boilerplate. Key options include `frozen=True` for immutability and automatic `__hash__`, `order=True` for comparison operators, and `slots=True` (Python 3.10+) for memory-efficient slot-based storage.

How to think about it

@dataclass is a decorator that reads your field annotations and writes the dunder boilerplate you’d otherwise type by hand — __init__, __repr__, __eq__. What an interviewer actually wants is for you to say what it generates, which options change that, and the one gotcha everyone hits: a mutable default like tags: list = [] is rejected outright.

A worked example

from dataclasses import dataclass, field

# A plain @dataclass generates __init__, __repr__, and __eq__ for you
@dataclass
class Point:
    x: float
    y: float
    z: float = 0.0

p1, p2, p3 = Point(1.0, 2.0), Point(1.0, 2.0), Point(1.0, 2.0, 3.0)
print("repr:", p1)
print("eq p1==p2:", p1 == p2)        # __eq__ compares fields
print("eq p1==p3:", p1 == p3)

# frozen + order add immutability/hashing and the comparison operators
@dataclass(frozen=True, order=True)
class Vector:
    x: float
    y: float
    tags: list = field(default_factory=list, compare=False)   # excluded from ==/<

v1, v2 = Vector(1.0, 2.0), Vector(3.0, 0.5)
print("v1 < v2?", v1 < v2)                              # order=True -> __lt__ etc.
print("hashable?", hash(v1) == hash(Vector(1.0, 2.0)))  # frozen=True -> __hash__
print("set of vectors:", sorted({v1, v2}))              # so it works in a set

# field() gives per-field control: safe mutable defaults, hidden fields
@dataclass
class ModelConfig:
    name: str
    lr: float = 0.001
    layers: list = field(default_factory=list)
    _internal: str = field(default="secret", repr=False, compare=False)

print("config:", ModelConfig("mlp", layers=[128, 64]))  # _internal hidden from repr
repr: Point(x=1.0, y=2.0, z=0.0)
eq p1==p2: True
eq p1==p3: False
v1 < v2? True
hashable? True
set of vectors: [Vector(x=1.0, y=2.0, tags=[]), Vector(x=3.0, y=0.5, tags=[])]
config: ModelConfig(name='mlp', lr=0.001, layers=[128, 64])

Three flags carry most of the value. frozen=True makes instances immutable and gives them a __hash__, so they can live in sets and as dict keys. order=True synthesises __lt__ and friends, comparing fields left to right. And field(...) tunes a single field — compare=False keeps tags out of equality and hashing, repr=False hides _internal from the printed form.

slots=True (Python 3.10+)

@dataclass(slots=True)
class Pixel:
    x: int
    y: int
    color: str

This is the same memory win as a hand-written __slots__ — no __dict__, lower per-instance cost, faster attribute access — without typing the slot names yourself. Worth it when you’ll create millions of instances.

Learn it properly dataclasses

Keep practising

All Python questions

Explore further

Skip to content