Python Data Classes

Introduction

Data classes (Python 3.7+) are a clean way to define classes that are mainly used for storing data: configs, DTOs, models, request objects, etc. They automatically generate __init__, __repr__, __eq__ and more.

1. Basic Data Class

from dataclasses import dataclass

@dataclass
class User:
    username: str
    age: int

u = User("Kaloyan", 12)
print(u.username, u.age)
    

You get an auto-generated __init__, nice __repr__, and comparisons.

2. Default Values

@dataclass
class Settings:
    theme: str = "dark"
    notifications: bool = True

s = Settings()
print(s.theme)  # dark
    

3. Type Hints Are Required

Data classes rely on type hints. Every field should have a type annotation.

@dataclass
class Product:
    name: str
    price: float
    in_stock: bool = True
    

4. Comparison Support

@dataclass
class Score:
    value: int

a = Score(10)
b = Score(10)
print(a == b)  # True
    

5. frozen=True (Immutable Objects)

@dataclass(frozen=True)
class Config:
    api_key: str
    timeout: int = 30

cfg = Config("ABC")
# cfg.timeout = 10  # ERROR: cannot assign to field
    

6. order=True (Sortable)

@dataclass(order=True)
class Player:
    score: int
    name: str

players = [
    Player(100, "A"),
    Player(250, "B"),
    Player(150, "C"),
]

players.sort()
print(players)  # sorted by score
    

7. field() for Advanced Options

from dataclasses import dataclass, field
from typing import List

@dataclass
class Session:
    user: str
    roles: List[str] = field(default_factory=list)

s = Session("Kaloyan")
s.roles.append("admin")
    

Use default_factory for lists/dicts to avoid shared mutable defaults.

8. Post-Init Logic

@dataclass
class Rectangle:
    width: float
    height: float
    area: float = 0

    def __post_init__(self):
        self.area = self.width * self.height

r = Rectangle(4, 5)
print(r.area)  # 20
    

9. asdict() and astuple()

from dataclasses import asdict, astuple

user = User("Kaloyan", 12)
print(asdict(user))
print(astuple(user))
    

10. Inheritance with Data Classes

@dataclass
class BaseUser:
    username: str

@dataclass
class ProUser(BaseUser):
    plan: str = "pro"

u = ProUser("Kaloyan")
print(u.username, u.plan)
    

11. Frozen + Hashable

Frozen data classes can be used as dict keys or in sets.

@dataclass(frozen=True)
class Point:
    x: int
    y: int

p = Point(1, 2)
points = {p}
    

12. When to Use Data Classes

13. When Not to Use Them

Summary