stackademic

The leading education platform for anyone with an interest in software development.

Python Dataclasses

Generate boilerplate-free classes for structured data with the dataclass decorator

Overview

The @dataclass decorator auto-generates __init__, __repr__, and __eq__ from annotated class fields, eliminating repetitive boilerplate. It is ideal for plain data containers where you would otherwise write tedious constructors. Options like frozen, order, and field give fine control over immutability, comparison, and defaults.

Syntax / Usage

Decorate a class and declare fields with type annotations. The decorator wires up the dunder methods.

from dataclasses import dataclass, field

@dataclass
class Point:
    x: float
    y: float
    label: str = "origin"          # field with a default

@dataclass(frozen=True, order=True)
class Version:
    major: int
    minor: int
    tags: list[str] = field(default_factory=list)  # mutable default

p = Point(1.0, 2.0)
print(p)              # Point(x=1.0, y=2.0, label='origin')
print(p == Point(1.0, 2.0))  # True

Use field(default_factory=...) for mutable defaults; a bare [] default would be shared across instances.

Examples

An immutable, sortable record. frozen=True makes instances hashable and read-only:

from dataclasses import dataclass

@dataclass(frozen=True, order=True)
class Employee:
    salary: int
    name: str

team = [Employee(90_000, "ada"), Employee(120_000, "linus")]
print(sorted(team)[0].name)  # 'ada' — sorted by salary first

Post-init validation and derived fields with __post_init__:

from dataclasses import dataclass, field

@dataclass
class Rectangle:
    width: float
    height: float
    area: float = field(init=False)

    def __post_init__(self) -> None:
        if self.width <= 0 or self.height <= 0:
            raise ValueError("dimensions must be positive")
        self.area = self.width * self.height

print(Rectangle(3, 4).area)  # 12

Common Mistakes

  • Using a mutable default like field: list = [], which raises a ValueError—use default_factory
  • Placing fields with defaults before fields without them, causing a TypeError
  • Expecting frozen=True instances to be mutable; assignment raises FrozenInstanceError
  • Adding heavy behavior to dataclasses when a regular class better expresses the intent
  • Forgetting that eq=False also disables hashing behavior you might rely on

See Also

python-type-hints python-classes python-iterators-protocol