Skip to main content
Dataclasses were introduced in Python 3.7 (PEP 557) to solve a specific, common problem: when you create a class whose primary purpose is to hold data, you inevitably write the same boilerplate over and over — __init__, __repr__, __eq__. The @dataclass decorator eliminates this entirely. Python generates those methods automatically from your type-annotated fields, giving you a clean, readable data model with almost no ceremony. This page covers everything from basic usage to frozen instances, ordering, class variables, utility functions, and how dataclasses compare to Pydantic’s BaseModel.

What is a Dataclass?

A dataclass is a class decorated with @dataclass that automatically generates common dunder methods based on its type-annotated attributes. Import the decorator from the dataclasses module:

Before and After

Without dataclass — verbose boilerplate:
With dataclass — concise and clear:
Python automatically generates __init__(), __repr__(), and __eq__() from the type-annotated fields.

Fields and Default Values

Every type-annotated attribute becomes a dataclass field:
Fields can have default values to make them optional:
Never use a mutable object (like a list or dict) as a default value directly. All instances would share the same object, causing hard-to-debug bugs:
Use field(default_factory=...) instead:

Adding Methods

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

Immutable Dataclasses with frozen=True

Pass frozen=True to make all instances immutable. Attempting to modify a field raises a FrozenInstanceError:
Frozen dataclasses are hashable by default, making them suitable as dictionary keys or set members.

Ordering with order=True

Pass order=True to generate comparison methods (<, <=, >, >=) based on field values in declaration order:

Decorator Options Summary

Instance Variables vs. Class Variables

Instance Variables

Type-annotated attributes become instance fields — each object gets its own copy:

Class Variables with ClassVar

Use ClassVar from typing to declare class-level attributes that are shared by all instances. Dataclasses exclude ClassVar fields from __init__ and __repr__:

Utility Functions

The dataclasses module provides three helpful utility functions:

asdict() — Convert to Dictionary

astuple() — Convert to Tuple

replace() — Create a Modified Copy

Dataclass vs. Pydantic BaseModel

Both are used for structured data, but they serve different purposes:

Type Validation Comparison

Dataclass — no validation:
Pydantic — validates and coerces:

When to Use Each

Use @dataclass when:
  • You’re building internal domain or business models.
  • You already trust the data (it was created by your own code).
  • You want a lightweight container without validation overhead.
  • Examples: Product, Employee, Point, Config
Use Pydantic BaseModel when:
  • You’re accepting external input (HTTP requests, JSON files, user forms).
  • You need automatic type coercion and detailed error messages.
  • You’re building FastAPI request/response models.
  • Examples: API request schemas, response bodies, configuration settings
Rule of thumb: @dataclass“I already trust this data; I just need a convenient container.” Pydantic BaseModel“I don’t trust this data yet; validate it before I use it.”