For more on classes, refer Object Oriented Python.
A Python dataclass lets you define classes that are only used to store data. It saves you some boilerplate; by writing @dataclass you can generate __init__(), __repr__() and __eq__() automatically.

Introduction

from dataclasses import dataclass
 
@dataclass
class Book:
    pages: int
    author: str
 
demo = book('100', 'Pippa Python')
print(demo.pages)
print(demo.author)

This class comes with basic functionality already implemented. A minimal regular class would’ve looked like this:

class Book:
    def __init__(self, pages: int, author: str):
        self.pages = pages
        self.author = author

By default dataclasses also provide a repr method for string representation.
That is equivalent to:

class Book:
    def __init__(self, pages: int, author: str):
        self.pages = pages
        self.author = author
 
    def __repr__(self):
        return (f'{self.__class__.__name__}'
                f'(pages={self.pages!r}), (author={self.author!r})'
        )
 
    def __eq__(self, other):
        if other.__class__ is not self.__class__:
            return NotImplemented
        return (self.pages, self.author) == (other.pages, other.author)

Well, that was a lot of boilerplate!

Features

You can add default values, type hints, etc. You can also add methods.

from dataclasses import dataclass
 
@dataclass
class Position:
    name: str
    longitude: float = 0.0
    latitude: float = 0.0
    nearest: list[float] = []
 
    def distance(self, other) -> float:
        pass # use trigonometry or something

You can also override the __repr__ or __str__ methods to represent the data class however you want.

You can also subclass dataclasses via inheritance. But keep in mind that if a parameter has a default value, all following parameters must also have a default value. As an example:

@dataclass
class Capital(Position):
    country: str
# this is going to crash with "non default arugument 'country' follows default argument"

because this tries to create a constructor like:

def __init__(name: str, longitude: float = 0.0, latitude: float = 0.0, nearest: list[float] = [], country: str):
    pass

So the correct version is:

@dataclass
class Capital(Position):
    country: str = 'Polygondwanaland'

Forms for the decorator

The @dataclass decorator has two forms - one without any parantheses or parameters, and one with those. The following parameters are supported:

  • init: Add __init__() method? Default is True.
  • repr: Add __repr__() method? Default is True.
  • eq: Add __eq__() method? Default is True.
  • order: Add ordering methods? Default is False.
  • unsafe_hash: Force the addition of a __hash__() method? Default is False.
  • frozen: If True, assigning to fields raises an exception. Default is False.
    The order thing just makes comparison easier - and sorting too.
    ex.
from dataclasses import dataclass
 
@dataclass(order=True)
class Book:
    name: str
    pages: int
 
book1 = Book('Short', 100)
book2 = Book('Long', 800)
 
print(book2 > book1)
# True

Optimisations

Slots can be used to make classes faster and use less memory. Data classes have explicit syntax for working with slots, but the normal way of creating slots works with dataclasses as well (i.e. using __slots__).

from dataclasses import dataclass
 
@dataclass
class SimpleBook:
    name: str
    author: str
 
@dataclass
class SlotBook:
    __slots__ = ['name', 'author']
    name: str
    author: str

Slot classes can be faster to work with. You can easily have any dataclass have slots by providing the slots=True argument.

from dataclasses import dataclass
 
@dataclass(slots=True)
class Book:
    name: str
    author: str