Skip to main content
Whenever you write a class whose main job is to hold a group of related values, you end up writing the same boilerplate over and over: __init__, __repr__, __eq__. Dataclasses, introduced in Python 3.7, generate all of that automatically from your type-annotated field declarations — leaving you with a clean, expressive data container in a handful of lines.

The Problem Dataclasses Solve

Field Definitions and Default Values

Every type-annotated class attribute becomes a dataclass field and a parameter in the generated __init__. Fields without defaults must come before fields with defaults (same rule as regular function parameters).

field() for Advanced Field Configuration

When your default value is a mutable object (list, dict, set), you must use field(default_factory=...) — otherwise all instances share the same mutable object.
field() also lets you hide a field from __repr__ or exclude it from __init__:

Frozen Dataclasses (Immutable)

Pass frozen=True to make instances immutable. Attempting to assign to a field raises FrozenInstanceError. Frozen dataclasses are also hashable by default, so you can use them as dictionary keys or in sets.

Ordering Support

Add order=True to generate __lt__, __le__, __gt__, __ge__ methods based on all fields in declaration order:

Utility Functions

Class Variables vs Instance Fields

Use ClassVar from typing to declare attributes that belong to the class, not individual instances. Dataclasses ignore ClassVar fields — they don’t appear in __init__ or __repr__.

Adding Methods

Dataclasses are still regular classes — you can add any methods you need:

Dataclass vs NamedTuple vs Pydantic Model

Choosing the right container depends on what you need to do with the data.

Type coercion comparison

When to Use Each

You trust the data source (it comes from inside your application) and you just need a convenient, readable container. Internal domain models — Product, Order, Employee, Point, Config — are perfect candidates.
You want a lightweight, always-immutable, hashable record and you never need to add methods or complex defaults.
Data comes from an external source you don’t control: an HTTP request body, a JSON file, a CSV import, user input. Use Pydantic when you need validation, coercion, and clear error messages.
Rule of thumb: If you already trust the data, use @dataclass. If you’re receiving data from the outside world and need to validate it, use a Pydantic BaseModel.