Focused practice · 9 min read

Python Dataclass Practice Guide: Fields

A dataclass is a compact way to say that a class is mostly data. It generates the repetitive methods, but it is still a normal Python class. Understanding what it generates, and what it does not, prevents both boilerplate and false expectations.

Declare the fields

Write annotated class attributes. The decorator uses them to generate __init__, __repr__, and __eq__. Construction is positional unless you use keyword arguments. The generated repr is useful in logs and test failures.

from dataclasses import dataclass

@dataclass
class Point:
    x: int
    y: int

print(Point(2, 3))

A data-focused class

Place defaults in the right order

A field with a default can be omitted. A field without one must still be supplied, so it cannot follow a defaulted field in the class body. Reorder the fields or give the earlier field a default as well.

from dataclasses import dataclass

@dataclass
class User:
    name: str
    active: bool = True

print(User("Ada"))
print(User("Grace", False))

Required then optional

Equality is field-based

Two dataclass instances compare equal when their fields compare equal, even if they are different objects. This is convenient in tests, but nested mutable fields still follow their own equality rules. Do not confuse equality with identity.

from dataclasses import dataclass

@dataclass
class Point:
    x: int
    y: int

print(Point(1, 2) == Point(1, 2))
print(Point(1, 2) is Point(1, 2))

Equal values, different objects

Convert with asdict

asdict recursively converts a dataclass instance into a dictionary. Lists, tuples, and nested dataclasses are converted too. It is handy for JSON-like output and assertions, but it is a copy, not a live view.

from dataclasses import dataclass, asdict

@dataclass
class Item:
    name: str
    price: float

print(asdict(Item("tea", 3.5)))

A plain dictionary

Use frozen for value objects

frozen=True prevents attribute assignment after construction. That makes an instance safer to share and hash, but it does not deep-freeze nested mutable values. Use it for small value objects, not as a blanket replacement for every class.

from dataclasses import dataclass

@dataclass(frozen=True)
class Item:
    name: str
    price: float

item = Item("tea", 3.5)
print(item.price)

An immutable record

Your practice checklist

Common questions

Do dataclasses validate types?

No. Annotations describe intent, but the generated __init__ does not enforce them at runtime.

Can a dataclass have methods?

Yes. It is a normal class; add methods, properties, or validation in __post_init__ when needed.

Is asdict a shallow copy?

It recursively converts dataclass values, but mutable objects inside the fields may still be shared. Inspect nested data when that matters.

Practice dataclasses

12 questions on fields, defaults, equality, asdict, and frozen instances.

Open practice

Keep reading: