Data classes are just regular classes that are geared towards storing state, rather than containing a lot of logic. Every time you create a class that mostly consists of attributes, you make a data class.

What the dataclasses module does is to make it easier to create data classes. It takes care of a lot of boilerplate for you.

This is especially useful when your data class must be hashable; because this requires a __hash__ method as well as an __eq__ method. If you add a custom __repr__ method for ease of debugging, that can become quite verbose:

class InventoryItem:
    '''Class for keeping track of an item in inventory.'''
    name: str
    unit_price: float
    quantity_on_hand: int = 0

    def __init__(
            self, 
            name: str, 
            unit_price: float,
            quantity_on_hand: int = 0
        ) -> None:
        self.name = name
        self.unit_price = unit_price
        self.quantity_on_hand = quantity_on_hand

    def total_cost(self) -> float:
        return self.unit_price * self.quantity_on_hand
    
    def __repr__(self) -> str:
        return (
            'InventoryItem('
            f'name={self.name!r}, unit_price={self.unit_price!r}, '
            f'quantity_on_hand={self.quantity_on_hand!r})'
        )

    def __hash__(self) -> int:
        return hash((self.name, self.unit_price, self.quantity_on_hand))

    def __eq__(self, other) -> bool:
        if not isinstance(other, InventoryItem):
            return NotImplemented
        return (
            (self.name, self.unit_price, self.quantity_on_hand) == 
            (other.name, other.unit_price, other.quantity_on_hand))

With dataclasses you can reduce it to:

from dataclasses import dataclass

@dataclass(unsafe_hash=True)
class InventoryItem:
    '''Class for keeping track of an item in inventory.'''
    name: str
    unit_price: float
    quantity_on_hand: int = 0

    def total_cost(self) -> float:
        return self.unit_price * self.quantity_on_hand

(Example based on the PEP example).

The same class decorator can also generate comparison methods (__lt__, __gt__, etc.) and handle immutability.

namedtuple classes are also data classes, but are immutable by default (as well as being sequences). dataclasses are much more flexible in this regard, and can easily be structured such that they can fill the same role as a namedtuple class.

The PEP was inspired by the attrs project, which can do even more (including slots, validators, converters, metadata, etc.).

If you want to see some examples, I recently used dataclasses for several of my Advent of Code solutions, see the solutions for day 7, day 8, day 11 and day 20.

If you want to use dataclasses module in Python versions < 3.7, then you could install the backported module (requires 3.6) or use the attrs project mentioned above.

Answer from Martijn Pieters on Stack Overflow
🌐
Python
docs.python.org › 3 › library › dataclasses.html
dataclasses — Data Classes
3 weeks ago - This has the same issue as the original example using class C. That is, two instances of class D that do not specify a value for x when creating a class instance will share the same copy of x. Because dataclasses just use normal Python class creation they also share this behavior.
🌐
Real Python
realpython.com › python-data-classes
Data Classes in Python (Guide) – Real Python
March 8, 2024 - Data classes do not implement a .__str__() method, so Python will fall back to the .__repr__() method. Let us implement a user-friendly representation of a PlayingCard: ... from dataclasses import dataclass @dataclass class PlayingCard: rank: str suit: str def __str__(self): return f'{self.suit}{self.rank}'
Discussions

python - What are data classes and how are they different from common classes? - Stack Overflow
If you want to see some examples, I recently used dataclasses for several of my Advent of Code solutions, see the solutions for day 7, day 8, day 11 and day 20. If you want to use dataclasses module in Python versions < 3.7, then you could install the backported module (requires 3.6) or use ... More on stackoverflow.com
🌐 stackoverflow.com
Why you should use Data Classes in Python
Neato! As a python noob, I had never heard of dataclasses until today and I'll definitely keep this in mind for the future. More on reddit.com
🌐 r/Python
74
611
September 16, 2022
Dataclass - what is it [for]?
The dataclass decorator helps you build, wait for it, data classes. In short, it takes care of some annoying things for you: defining a couple of methods, such as init, str, repr, eq, gt, etc. It does tuple equality and comparison. It also defines match args for use in match statements. It lets you freeze instances, making them immutable. It's quite convenient honestly. Say you're coding a 🎲 die roll challenge for an rpg, you could write a RollResult class that holds the roll and the roll/challenge ratio: @dataclass(frozen=True) class RollResult: roll: int ratio: float And you can use it wherever it makes sense: if result.ratio >= 1: print("success") match result: case RollResult(20, _): print("nat 20") More on reddit.com
🌐 r/learnpython
33
18
May 22, 2025
Any reason not to use dataclasses everywhere?
Absolutely use data classes when they do the job. Cases when this is not true (or it's awkward): custom init method custom new method various patterns that use inheritance if you want different names for the attributes,. including implementing encapsulation probably more things :) Changing later might have some cost, so use dataclasses when you are fairly certain you won't need those things. This is still a lot of cases, I use them often. More on reddit.com
🌐 r/Python
70
44
October 24, 2022
🌐
GeeksforGeeks
geeksforgeeks.org › python › understanding-python-dataclasses
Understanding Python Dataclasses - GeeksforGeeks
July 15, 2025 - DataClasses are like normal classes in Python, but they have some basic functions like instantiation, comparing, and printing the classes already implemented.
🌐
DataCamp
datacamp.com › tutorial › python-data-classes
Python Data Classes: A Comprehensive Tutorial | DataCamp
March 15, 2024 - Despite all their features, data ... functionality. Here is the Exercise class again: from dataclasses import dataclass @dataclass class Exercise: name: str reps: int sets: int weight: float ex1 = Exercise("Bench press", 10, 3, 52.5) # Verifying Exercise is a regular class ex1.name ...
🌐
Dataquest
dataquest.io › blog › how-to-use-python-data-classes
How to Use Python Data Classes (A Beginner's Guide) – Dataquest
May 12, 2025 - Notice that we used default attributes to make the example shorter. In this case, the comparison is valid because the dataclass creates behind the scenes an __eq__ method, which performs the comparison. Without the decorator, we'd have to create this method ourselves. The same comparison would result in a different outcome if using a standard Python ...
🌐
Packetcoders
packetcoders.io › python-data-classes
Python - Data Classes
February 16, 2022 - $ cat interface_dataclass.py from dataclasses import dataclass @dataclass class Interface: name: str speed: int = 1000 mtu: int = 1500 Interface(name='Ethernet1/1', speed="1000GB", mtu=1500)
🌐
Mimo
mimo.org › glossary › python › data-class
Python Data Class: Syntax, Usage, and Examples
@dataclass class Rectangle: width: int height: int r1 = Rectangle(10, 20) r2 = Rectangle(10, 20) print(r1 == r2) # True · Behind the scenes, Python generates a full __eq__() method based on the fields. Here's a more advanced example of a data class Python might use in a finance app:
Find elsewhere
🌐
Hamy
hamy.xyz › blog › 2023-10-python-dataclasses
Python Dataclass best practices (and why you should use them) - HAMY
""" Example 1: Simple dataclasses * Temperature, Unit pairs """ print("Example 1: Simple dataclasses") class TemperatureUnit(Enum): CELSIUS = 1 FARENHEIGHT = 2 @dataclass class Temperature: TemperatureMagnitude: float Unit: TemperatureUnit temperature_tuple = (50.0, TemperatureUnit.CELSIUS) ...
Top answer
1 of 5
537

Data classes are just regular classes that are geared towards storing state, rather than containing a lot of logic. Every time you create a class that mostly consists of attributes, you make a data class.

What the dataclasses module does is to make it easier to create data classes. It takes care of a lot of boilerplate for you.

This is especially useful when your data class must be hashable; because this requires a __hash__ method as well as an __eq__ method. If you add a custom __repr__ method for ease of debugging, that can become quite verbose:

class InventoryItem:
    '''Class for keeping track of an item in inventory.'''
    name: str
    unit_price: float
    quantity_on_hand: int = 0

    def __init__(
            self, 
            name: str, 
            unit_price: float,
            quantity_on_hand: int = 0
        ) -> None:
        self.name = name
        self.unit_price = unit_price
        self.quantity_on_hand = quantity_on_hand

    def total_cost(self) -> float:
        return self.unit_price * self.quantity_on_hand
    
    def __repr__(self) -> str:
        return (
            'InventoryItem('
            f'name={self.name!r}, unit_price={self.unit_price!r}, '
            f'quantity_on_hand={self.quantity_on_hand!r})'
        )

    def __hash__(self) -> int:
        return hash((self.name, self.unit_price, self.quantity_on_hand))

    def __eq__(self, other) -> bool:
        if not isinstance(other, InventoryItem):
            return NotImplemented
        return (
            (self.name, self.unit_price, self.quantity_on_hand) == 
            (other.name, other.unit_price, other.quantity_on_hand))

With dataclasses you can reduce it to:

from dataclasses import dataclass

@dataclass(unsafe_hash=True)
class InventoryItem:
    '''Class for keeping track of an item in inventory.'''
    name: str
    unit_price: float
    quantity_on_hand: int = 0

    def total_cost(self) -> float:
        return self.unit_price * self.quantity_on_hand

(Example based on the PEP example).

The same class decorator can also generate comparison methods (__lt__, __gt__, etc.) and handle immutability.

namedtuple classes are also data classes, but are immutable by default (as well as being sequences). dataclasses are much more flexible in this regard, and can easily be structured such that they can fill the same role as a namedtuple class.

The PEP was inspired by the attrs project, which can do even more (including slots, validators, converters, metadata, etc.).

If you want to see some examples, I recently used dataclasses for several of my Advent of Code solutions, see the solutions for day 7, day 8, day 11 and day 20.

If you want to use dataclasses module in Python versions < 3.7, then you could install the backported module (requires 3.6) or use the attrs project mentioned above.

2 of 5
277

Overview

The question has been addressed. However, this answer adds some practical examples to aid in the basic understanding of dataclasses.

What exactly are python data classes and when is it best to use them?

  1. code generators: generate boilerplate code; you can choose to implement special methods in a regular class or have a dataclass implement them automatically.
  2. data containers: structures that hold data (e.g. tuples and dicts), often with dotted, attribute access such as classes, namedtuple and others.

"mutable namedtuples with default[s]"

Here is what the latter phrase means:

  • mutable: by default, dataclass attributes can be reassigned. You can optionally make them immutable (see Examples below).
  • namedtuple: you have dotted, attribute access like a namedtuple or a regular class.
  • default: you can assign default values to attributes.

Compared to common classes, you primarily save on typing boilerplate code.


Features

This is an overview of dataclass features (TL;DR? See the Summary Table in the next section).

What you get

Here are features you get by default from dataclasses.

Attributes + Representation + Comparison

import dataclasses


@dataclasses.dataclass
#@dataclasses.dataclass()                                       # alternative
class Color:
    r : int = 0
    g : int = 0
    b : int = 0

These defaults are provided by automatically setting the following keywords to True:

@dataclasses.dataclass(init=True, repr=True, eq=True)

What you can turn on

Additional features are available if the appropriate keywords are set to True.

Order

@dataclasses.dataclass(order=True)
class Color:
    r : int = 0
    g : int = 0
    b : int = 0

The ordering methods are now implemented (overloading operators: < > <= >=), similarly to functools.total_ordering with stronger equality tests.

Hashable, Mutable

@dataclasses.dataclass(unsafe_hash=True)                        # override base `__hash__`
class Color:
    ...

Although the object is potentially mutable (possibly undesired), a hash is implemented.

Hashable, Immutable

@dataclasses.dataclass(frozen=True)                             # `eq=True` (default) to be immutable 
class Color:
    ...

A hash is now implemented and changing the object or assigning to attributes is disallowed.

Overall, the object is hashable if either unsafe_hash=True or frozen=True.

See also the original hashing logic table with more details.

Optimization

@dataclasses.dataclass(slots=True)              # py310+
class SlottedColor:
    #__slots__ = ["r", "b", "g"]                # alternative
    r : int
    g : int
    b : int

The object size is now reduced:

>>> imp sys
>>> sys.getsizeof(Color)
1056
>>> sys.getsizeof(SlottedColor)
888

slots=True was added in Python 3.10. (Thanks @ajskateboarder).

In some circumstances, slots=True/__slots__ also improves the speed of creating instances and accessing attributes. Also, slots do not allow default assignments; otherwise, a ValueError is raised. If __slot__ already exists, slots=True will cause a TypeError.

See more on slots in this blog post.

See more on arguments added in Python 3.10+: match_args, kw_only, slots, weakref_slot.

What you don't get

To get the following features, special methods must be manually implemented:

Unpacking

@dataclasses.dataclass
class Color:
    r : int = 0
    g : int = 0
    b : int = 0

    def __iter__(self):
        yield from dataclasses.astuple(self)

Summary Table

+----------------------+----------------------+----------------------------------------------------+-----------------------------------------+
|       Feature        |       Keyword        |                      Example                       |           Implement in a Class          |
+----------------------+----------------------+----------------------------------------------------+-----------------------------------------+
| Attributes           |  init                |  Color().r -> 0                                    |  __init__                               |
| Representation       |  repr                |  Color() -> Color(r=0, g=0, b=0)                   |  __repr__                               |
| Comparision*         |  eq                  |  Color() == Color(0, 0, 0) -> True                 |  __eq__                                 |
|                      |                      |                                                    |                                         |
| Order                |  order               |  sorted([Color(0, 50, 0), Color()]) -> ...         |  __lt__, __le__, __gt__, __ge__         |
| Hashable             |  unsafe_hash/frozen  |  {Color(), {Color()}} -> {Color(r=0, g=0, b=0)}    |  __hash__                               |
| Immutable            |  frozen + eq         |  Color().r = 10 -> TypeError                       |  __setattr__, __delattr__               |
| Optimization         |  slots               |  sys.getsizeof(SlottedColor) -> 888                |  __slots__                              |
|                      |                      |                                                    |                                         |
| Unpacking+           |  -                   |  r, g, b = Color()                                 |  __iter__                               |
+----------------------+----------------------+----------------------------------------------------+-----------------------------------------+

* __ne__ is not needed and thus not implemented.

+These methods are not automatically generated and require manual implementation in a dataclass.


Additional features

Post-initialization

@dataclasses.dataclass
class RGBA:
    r : int = 0
    g : int = 0
    b : int = 0
    a : float = 1.0

    def __post_init__(self):
        self.a : int =  int(self.a * 255)


RGBA(127, 0, 255, 0.5)
# RGBA(r=127, g=0, b=255, a=127)

Inheritance

@dataclasses.dataclass
class RGBA(Color):
    a : int = 0

Conversions

Convert a dataclass to a tuple or a dict, recursively:

>>> dataclasses.astuple(Color(128, 0, 255))
(128, 0, 255)
>>> dataclasses.asdict(Color(128, 0, 255))
{'r': 128, 'g': 0, 'b': 255}

Limitations

  • Lacks mechanisms to handle starred arguments
  • Working with nested dataclasses can be complicated

References

  • R. Hettinger's talk on Dataclasses: The code generator to end all code generators
  • T. Hunner's talk on Easier Classes: Python Classes Without All the Cruft
  • Python's documentation on hashing details
  • Real Python's guide on The Ultimate Guide to Data Classes in Python 3.7
  • A. Shaw's blog post on A brief tour of Python 3.7 data classes
  • E. Smith's github repository on dataclasses
🌐
Python
peps.python.org › pep-0557
PEP 557 – Data Classes | peps.python.org
A previous version of this PEP specified that init=False fields would be copied from the source object to the newly created object after __init__ returned, but that was deemed to be inconsistent with using __init__ and __post_init__ to initialize the new object. For example, consider this case: @dataclass class Square: length: float area: float = field(init=False, default=0.0) def __post_init__(self): self.area = self.length * self.length s1 = Square(1.0) s2 = replace(s1, length=2.0)
🌐
Medium
medium.com › @laurentkubaski › python-data-classes-f98f8368f5c2
Python Data Classes. This is a quick intro to Python Data… | by Laurent Kubaski | Medium
November 25, 2025 - @dataclass(unsafe_hash=True) class MyDataClass: var1: str var2: int # non-frozen Data Class: __hash__() method is STILL generated because of unsafe_hash=True assert [name for (name, value) in inspect.getmembers(MyDataClass, predicate=inspect.isfunction)] == ['__eq__', '__hash__', '__init__', '__repr__'] my_dataclass = MyDataClass("Hello", 5) assert my_dataclass.__hash__ is not None · The official Python documentation is amazingly unclear on why you would want to do this: “This might be the case if your class is logically immutable but can still be mutated.
🌐
Reddit
reddit.com › r/python › why you should use data classes in python
r/Python on Reddit: Why you should use Data Classes in Python
September 16, 2022 - Namedtuples in Python also do so while being more lightweight than data classes since they’re POD and don’t require all the OO bloat. ... I'm going to save this article and try using data classes for Advent of Code this year. ... I went and did an Advent of Code problem to try our data classes. from dataclasses import dataclass, field @dataclass class Spaceship: mass: int fuel_for_mass: int = field(init=False) fuel_for_fuel: int = field(init=False) fuel_total: int = field(init=False) def __post_init__(self): self.fuel_for_mass = self.mass//3 - 2 self.fuel_for_fuel = 0 fuel_added = self.fue
🌐
InfoWorld
infoworld.com › home › software development › programming languages › python
How to use Python dataclasses | InfoWorld
October 22, 2025 - In this example, we’ve created a __post_init__ method to set shelf_id to None if the book’s condition is initialized as "Discarded". Note how we use field to initialize shelf_id, and pass init as False to field. This means shelf_id won’t be initialized in __init__, but it is registered as a field with the dataclass overall, with type information. Another way to customize Python dataclass setup is to use the InitVar type.
🌐
Python
typing.python.org › en › latest › spec › dataclasses.html
Dataclasses — typing documentation
A dataclass field may be annotated with Final[...]. For example, x: Final[int] in a dataclass body specifies a dataclass field x, which will be initialized in the generated __init__ and cannot be assigned to thereafter. A Final dataclass field initialized in the class body is not a class attribute ...
🌐
Pydantic
docs.pydantic.dev › latest › concepts › dataclasses
Dataclasses - Pydantic Validation
While Pydantic dataclasses support the extra configuration value, some default behavior of stdlib dataclasses may prevail. For example, any extra fields present on a Pydantic dataclass with extra set to 'allow' are omitted in the dataclass' string representation.
🌐
Medium
medium.com › @pouyahallaj › python-data-classes-the-key-to-clean-maintainable-code-a76a740d9884
Python Data Classes: The Key to Clean, Maintainable Code
June 1, 2023 - Python data classes seamlessly integrate with type hints, enhancing code clarity, enabling static type checking, and improving maintainability. Let’s explore how type hints can be leveraged with data classes. To annotate fields in a data class, you can simply specify the desired type after the field name. Here’s an example: from dataclasses import dataclass @dataclass class Point: x: float y: float
🌐
Reddit
reddit.com › r/learnpython › dataclass - what is it [for]?
r/learnpython on Reddit: Dataclass - what is it [for]?
May 22, 2025 -

I've been learning OOP but the dataclass decorator's use case sort of escapes me.

I understand classes and methods superficially but I quite don't understand how it differs from just creating a regular class. What's the advantage of using a dataclass?

How does it work and what is it for? (ELI5, please!)


My use case would be a collection of constants. I was wondering if I should be using dataclasses...

class MyCreatures:
        T_REX_CALLNAME = "t-rex"
        T_REX_RESPONSE = "The awesome king of Dinosaurs!"
        PTERODACTYL_CALLNAME = "pterodactyl"
        PTERODACTYL_RESPONSE = "The flying Menace!"
        ...

 def check_dino():
        name = input("Please give a dinosaur: ")
        if name == MyCreature.T_REX_CALLNAME:
                print(MyCreatures.T_REX_RESPONSE)
        if name = ...

Halp?

🌐
KDnuggets
kdnuggets.com › how-to-use-pythons-dataclass-to-write-less-code
How to Use Python’s dataclass to Write Less Code - KDnuggets
September 4, 2025 - Python enforces this to avoid confusion (just like function arguments). If you want more control — say you don’t want a field to be included in __repr__, or you want to set a default after initialization — you can use field(): from dataclasses import dataclass, field @dataclass class User: name: str password: str = field(repr=False) # Hide from __repr__
🌐
DEV Community
dev.to › omrigm › why-you-should-use-python-data-classes-48po
Why You Should Use Python Data Classes - DEV Community
January 8, 2022 - When we try to print the slow_tesla object, we see the actual values of the object, not the object's address, unlike the previous example. We can compare two objects without any need for us to implement special methods. Same as regular python classes, inheritance can come to our advantage here too, no need to deal with the parent class construction: from dataclasses import dataclass @dataclass class Car: color: str manufacturer: str top_speed_km: int @dataclass class ElectricCar(Car): battery_capacity_kwh: int maximum_range_km: int white_tesla_model_3 = ElectricCar(color='white', manufacturer='Tesla', top_speed_km=261, battery_capacity_kwh=50, maximum_range_km=455) print(white_tesla_model_3) # ElectricCar(color='white', manufacturer='Tesla', top_speed_km=261, battery_capacity_kwh=50, maximum_range_km=455)