Dataclasses: Boilerplate-Free Data Classes
Python 3.7 introduced @dataclass โ a decorator that automatically generates __init__, __repr__, __eq__, and more from class annotations.
from dataclasses import dataclass, field
# Without dataclass โ lots of boilerplate
class PointOld:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Point(x={self.x}, y={self.y})"
def __eq__(self, other):
return self.x == other.x and self.y == other.y
# With dataclass โ clean and concise
@dataclass
class Point:
x: float
y: float
p1 = Point(1.0, 2.0)
p2 = Point(1.0, 2.0)
print(p1) # Point(x=1.0, y=2.0) โ __repr__ auto-generated
print(p1 == p2) # True โ __eq__ auto-generated
print(p1.x) # 1.0Dataclass Options
from dataclasses import dataclass, field
from datetime import datetime
from typing import List
@dataclass
class Employee:
name: str
department: str
salary: float
start_date: datetime = field(default_factory=datetime.now)
skills: List[str] = field(default_factory=list) # Mutable default!
_id: int = field(default=0, init=False, repr=False) # Not in __init__
@dataclass(frozen=True) # Immutable โ like a named tuple
class Config:
host: str
port: int = 8080
debug: bool = False
# frozen=True makes instances hashable
config = Config("localhost", 5432)
# config.port = 3000 # FrozenInstanceError
@dataclass(order=True) # Generates __lt__, __le__, __gt__, __ge__
class Student:
gpa: float # First field used for comparison
name: str
students = [Student(3.8, "Alice"), Student(3.5, "Bob"), Student(3.9, "Carol")]
sorted(students) # Sorts by gpa (first field)Post-init Processing
@dataclass
class Rectangle:
width: float
height: float
area: float = field(init=False) # Computed, not passed to __init__
def __post_init__(self):
"""Called after __init__ โ validate or compute derived fields"""
if self.width <= 0 or self.height <= 0:
raise ValueError("Dimensions must be positive")
self.area = self.width * self.height
r = Rectangle(4, 5)
print(r.area) # 20.0Dataclass vs namedtuple vs regular class
| Feature | dataclass | namedtuple | regular class |
|---|---|---|---|
| Mutable | โ | โ | โ |
| Auto __init__ | โ | โ | โ |
| Auto __repr__ | โ | โ | โ |
| Hashable | Optional (frozen) | โ | Optional |
| Default values | โ | Limited | โ |
| Type hints | โ | Limited | Optional |
Key Takeaways
- @dataclass eliminates boilerplate: auto __init__, __repr__, __eq__
- field(default_factory=list): always use this for mutable defaults
- frozen=True: makes dataclass immutable and hashable
- order=True: auto-generates comparison methods based on field order
- __post_init__: for validation and computed fields
Practice Exercises
- Create a
Productdataclass with name, price, quantity. Add atotal_valueproperty computed in__post_init__. Make it orderable by price. - Create a frozen
Coordinatedataclass. Use it as a dictionary key to store elevation data. - Refactor the
BankAccountclass from Lesson 15 using@dataclass.