Python Snippet
Python Dataclass
Stop writing __init__, __repr__, and __eq__ by hand. Let @dataclass do it for you.
Last updated: October 2026
Quick answer: Add @dataclass above a class that stores data. Declare fields with type hints. Python auto-generates __init__, __repr__, and __eq__. For mutable defaults, use field(default_factory=list) instead of = [].
🎬 Interactive Live Demo
Click through the tabs to see how a regular class compares to its dataclass equivalent.
💡 Switch between tabs to see how much boilerplate @dataclass saves.
The Problem: Boilerplate Classes
A simple class that stores three fields requires a lot of repetitive code:
class User:
def __init__(self, name, email, age):
self.name = name
self.email = email
self.age = age
def __repr__(self):
return f"User(name={self.name!r}, email={self.email!r}, age={self.age!r})"
def __eq__(self, other):
if not isinstance(other, User):
return NotImplemented
return (self.name == other.name and
self.email == other.email and
self.age == other.age)
That's 18 lines to hold 3 fields. Multiply by every data class in your project.
The Solution: @dataclass
from dataclasses import dataclass
@dataclass
class User:
name: str
email: str
age: int
Six lines. Same functionality. The decorator generates __init__, __repr__, and __eq__ automatically.
user = User("Alice", "alice@example.com", 30)
print(user)
# User(name='Alice', email='alice@example.com', age=30)
user2 = User("Alice", "alice@example.com", 30)
print(user == user2) # True
Default Values and default_factory
For simple immutable defaults, use default:
@dataclass
class Product:
name: str
price: float = 0.0
in_stock: bool = True
For mutable defaults like lists or dicts, use field(default_factory=...):
from dataclasses import dataclass, field
@dataclass
class User:
name: str
tags: list[str] = field(default_factory=list)
metadata: dict = field(default_factory=dict)
Why not tags: list = []? Python raises ValueError at class definition time. Mutable defaults would be shared across all instances — the classic "list gets mutated everywhere" bug. default_factory creates a new list for each instance.
Frozen Dataclasses (Immutable)
Add frozen=True to make instances immutable and hashable:
from dataclasses import dataclass
@dataclass(frozen=True)
class Point:
x: float
y: float
p = Point(1.0, 2.0)
p.x = 5.0 # ❌ FrozenInstanceError
# Hashable — can be used as dict keys or in sets
cache = {p: "value"}
Frozen dataclasses are perfect for configuration objects, value types, and cache keys.
Adding Methods and Properties
Dataclasses are regular classes — add any methods you want:
@dataclass
class Product:
name: str
price: float
tax_rate: float = 0.1
@property
def total(self) -> float:
return self.price * (1 + self.tax_rate)
def is_expensive(self) -> bool:
return self.price > 100
p = Product("Laptop", 1200)
print(p.total) # 1320.0
print(p.is_expensive()) # True
Real-World Use Case: API Response Models
from dataclasses import dataclass, field
from datetime import datetime
import json
@dataclass
class APIUser:
id: int
name: str
email: str
created_at: datetime = field(default_factory=datetime.now)
tags: list[str] = field(default_factory=list)
@classmethod
def from_json(cls, data: dict):
return cls(
id=data["id"],
name=data["name"],
email=data["email"],
tags=data.get("tags", [])
)
# Parsing an API response becomes trivial
user = APIUser.from_json({
"id": 1,
"name": "Alice",
"email": "alice@example.com"
})
Dataclasses make parsing external data clean and typed. Combined with field(default_factory=...), they handle the common "missing optional field" case gracefully.
🎯 Dataclass vs Regular Class vs NamedTuple vs Pydantic
| Feature | dataclass | Regular Class | Pydantic |
|---|---|---|---|
| Boilerplate | Minimal | High | Minimal |
| Runtime Validation | No | No | Yes |
| Dependencies | Stdlib only | Stdlib only | Requires pydantic |
| Best For | Internal data, DTOs | Complex behavior | API inputs, config |
Choose @dataclass for internal data. Choose Pydantic when you need runtime validation (especially for API request bodies). Both are excellent — use them together in the same project.
⚠️ Common Mistakes
- Using mutable defaults directly.
tags: list = []raises an error at class definition. Usefield(default_factory=list). - Forgetting type hints. Fields without annotations aren't picked up by
@dataclass. Always annotate your fields. - Assuming dataclass validates at runtime. It doesn't. Type hints are documentation, not enforcement. Use Pydantic if you need validation.
- Mixing field order carelessly. Fields with defaults must come after fields without. Python will raise a
TypeError. - Using dataclass for heavy objects. Dataclasses are ideal for lightweight data. If your class has 20+ methods, a regular class is often clearer.
- Overusing frozen=True. Immutability is great, but it blocks inheritance patterns and can complicate ORM integration.
❓ Frequently Asked Questions
What is a dataclass in Python?
A dataclass is a Python decorator that automatically generates common methods like __init__, __repr__, and __eq__ for classes that primarily store data. It eliminates boilerplate and makes your code cleaner.
When should I use a dataclass?
Use dataclasses for any class that primarily holds data: configuration objects, API responses, DTOs, and simple domain models. If a class does more than store data, a regular class may be clearer.
What is the difference between default and default_factory?
default sets a fixed value shared by all instances. default_factory is a callable that creates a new value for each instance, which is required for mutable defaults like lists, dicts, and sets.
Can dataclasses have methods?
Yes. Dataclasses are regular classes. You can add any methods, properties, or class methods you want. The @dataclass decorator only auto-generates __init__, __repr__, and __eq__.
Are dataclasses faster than regular classes?
They are not faster at runtime, but they are faster to write. The generated methods are functionally identical to what you'd write by hand. The benefit is in developer time and code clarity.