Python 3.14 ·
✓ verified by execution on 2026-07-26
Writing a Python class often requires a lot of repetitive boilerplate code. You have to define __init__ to assign arguments to attributes, __repr__ for readable printing, and __eq__ for value comparison.
Python’s dataclasses module provides a powerful decorator that automates this entire process. By simply adding @dataclass above your class definition and providing type hints for your fields, Python writes the tedious dunder methods for you.
Basic Usage
The @dataclass decorator reads your class variables and automatically generates an __init__ method and a clean __repr__ method.
python
from dataclasses import dataclass@dataclassclass Point: x: int y: intp = Point(10, 20)print(p)
Output
Point(x=10, y=20)
Your output
Crucial detail: You must include type hints (like : int). The dataclass generator relies entirely on these annotations to determine which variables are actually fields. Without a type hint, the generator completely ignores the variable.
Value Equality
By default, standard Python classes compare object memory addresses (identity) when you use ==. Dataclasses are smarter: they automatically generate an __eq__ method that compares the object field-by-field.
If you want a field to have a default value, you simply assign it: is_active: bool = True. However, if you attempt to use an empty list [] as a default, Python will raise a ValueError because mutable defaults cause dangerous shared-state bugs across all instances.
To safely use dynamic or mutable defaults (like a fresh list for every new instance), you must use the field() function and provide a default_factory.
python
from dataclasses import dataclass, field@dataclassclass Team: name: str members: list = field(default_factory=list)t1 = Team('Red')t1.members.append('Alice')t2 = Team('Blue')print(f'{t1.name}: {t1.members}')print(f'{t2.name}: {t2.members}')
Output
Red: ['Alice']
Blue: []
Your output
Immutability: Frozen Dataclasses
Sometimes you want an object to be read-only after it is created. You can achieve this by passing frozen=True to the decorator. Any attempt to modify a field on a frozen dataclass raises a FrozenInstanceError.
python
from dataclasses import dataclass@dataclass(frozen=True)class Location: lat: float lon: floatloc = Location(37.77, -122.41)try: loc.lat = 0.0except Exception as e: print(type(e).__name__)
Output
FrozenInstanceError
Your output
Because frozen dataclasses cannot be modified, Python can safely generate a __hash__ method for them (as long as all of their fields are also hashable). This allows you to use your dataclasses as dictionary keys or inside sets.
python
from dataclasses import dataclass@dataclass(frozen=True)class Location: name: str# Because it is frozen and its fields are hashable, it can be a dict keyvisited = {Location('Paris'): True}print(visited[Location('Paris')])
Output
True
Your output
Note on Immutability:frozen=True only prevents reassignment of the object’s direct attributes (shallow immutability). If a field holds a mutable list, you can still append to that list!
Post-Initialization
Because the @dataclass decorator writes the __init__ method for you, you can’t put custom logic inside __init__ (like calculating a derived field). To solve this, dataclasses provide __post_init__, a special method that automatically runs immediately after the generated __init__ finishes.
Dataclasses drastically reduce visual clutter, keep your code DRY (Don’t Repeat Yourself), and represent the modern Pythonic standard for defining data-heavy structures.
Check yourself
Why must you provide type hints for fields when using `@dataclass`?
Reveal answer
The `@dataclass` decorator uses the type hints to know which variables belong to the class. — The `@dataclass` decorator relies entirely on PEP 526 variable annotations to know which fields belong to the class. If you leave out the type hint, the field is completely ignored by the dataclass generator.
What happens if you use an empty list `[]` as a default value for a field inside a dataclass?
Reveal answer
It raises a ValueError at class definition time to prevent the shared mutable default argument bug. — To protect you from the classic shared mutable state bug, `@dataclass` refuses to let you use `[]` or `{}` as default values. You must use `field(default_factory=list)` instead.
Are dataclasses faster than regular Python classes?
Reveal answer
No, they are standard Python classes with automatically generated boilerplate code. — Dataclasses are standard Python classes; they just have boilerplate code automatically written for them. They do not run any faster or slower than an equivalently written manual class.
What does `frozen=True` do to a dataclass?
Reveal answer
It prevents reassignment of the dataclass's own attributes, making it read-only. — Setting `frozen=True` prevents the reassignment of the dataclass's own attributes (shallow immutability). However, if a field contains a mutable object like a list, the contents of that list can still be modified.
Challenges
Challenge 1 +50 XP
Fix the bug! The `Playlist` dataclass tries to assign an empty list as the default value for `songs`. This raises a `ValueError` to prevent a shared-mutable-state bug. Fix the `songs` attribute by importing `field` from `dataclasses` and using `default_factory`.
python
Test 1 — expects "[]\n"
Need a hint? (−25% XP)
Change `songs: list = []` to `songs: list = field(default_factory=list)`. Don't forget to import `field`!
Show solution (0 XP)
from dataclasses import dataclass, field@dataclassclass Playlist: name: str songs: list = field(default_factory=list)p = Playlist('Workout')print(p.songs)
Challenge 2 +100 XP
Create a `User` dataclass with three fields: `username` (string), `email` (string), and `is_active` (boolean, defaulting to `True`). Instantiate a user named 'admin' and print the object.
python
Test 1 — expects "User(username='admin', email='admin@example.com', is_active=True)\n"
Need a hint? (−25% XP)
Use `@dataclass`, then define `username: str`, `email: str`, and `is_active: bool = True`.