What are data classes and how are they different from common classes?

class, python, python-3.7, python-dataclasses

Solution

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.

Problem

PEP 557 introduces data classes into the Python standard library. It says that by applying the `@dataclass` decorator shown below, it will generate "among other things, an `__init__()`". ``` from dataclasses import dataclass @dataclass 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 ``` It also says dataclasses are "mutable namedtuples with default", but I don't understand what this means, nor how data classes are different from common classes. What are data classes and when is it best to use them?

Original source

Related problems