@dataclass Basics
Overview
The `@dataclass` decorator in Python automatically generates boilerplate code for classes that primarily store data. When you add it to a class with type-hinted attributes, it automatically injects standard dunder methods behind the scenes: - `__init__()`: initializes the object attributes, returns `None`, raises `TypeError` if required arguments are missing. - `__repr__()`: provides a developer-friendly string representation, returns a `str`, raises `AttributeError` if expected fields are missing. - `__eq__()`: compares instances by field values instead of memory address, returns a `bool`, raises `AttributeError` if fields are missing. The mental model is a 'code generator': the decorator inspects the class at definition time, looks at the type hints, and injects these methods into the class dictionary as if you had typed them yourself. from dataclasses import dataclass @dataclass class BadUser: name: str tags: list = [] # Trap fires! Python evaluates default arguments once at class creation time, meaning all instances would share the same `list`. The `@dataclass` decorator actively protects against this by raising a `ValueError` when it detects a mutable default, covered fully in dataclass-field.
It eliminates the repetitive and error-prone work of writing `def __init__(self, x): self.x = x` for every data object.
Where used: Defining ORM models, Config structures, Returning structured data from functions
Why learn this
- You can define a class with 5 attributes in 6 lines of code instead of 20.
- Your classes automatically get a readable string representation (`__repr__()`) and value-based equality comparison (`__eq__()`).
Code walkthrough
from dataclasses import dataclass
@dataclass
class Product:
name: str
price: float
item = Product('Apple', 1.5)
print(item)
Focus: @dataclass
Aha moment
class NormalClass:
def __init__(self, name: str):
self.name = name
n1 = NormalClass('Bob')
n2 = NormalClass('Bob')
print(n1 == n2)
Prediction: Do two standard classes with identical attributes equal each other?
Common guess: True, because they have the same data.
It prints `False`. By default, custom classes use identity (memory address) for equality. The `@dataclass` decorator fixes this by automatically generating an `__eq__()` method for value equality.
Common mistakes
- Forgetting type hints: The `@dataclass` decorator only recognizes fields that have type annotations. A plain assignment like `x = 5` in the class body will be completely ignored by the `@dataclass` generator.
- Default mutable arguments: If you assign a mutable default like `items: list = []`, all instances will share the same `list`. The `@dataclass` decorator protects against this by raising a `ValueError`, but it catches beginners off guard.
Glossary
- type hints
- Annotations in Python code that indicate what type of data (like an integer or string) a variable should hold, e.g. `age: int`.
- boilerplate
- Standard pieces of code that have to be written repeatedly with little to no alteration, e.g. `def __init__(self, x): self.x = x`.
Recall questions
- Which three dunder methods does `@dataclass` automatically generate by default?
- How does the `@dataclass` decorator know which attributes to include in the generated methods?
Understanding checks
What does this code print?
Point(x=5)
The attribute `y` has no type hint, so `@dataclass` ignores it. It only generates an `__init__()` and `__repr__()` for the annotated `x` field.
What does this code print?
True
The `@dataclass` decorator automatically generates an `__eq__()` method that compares the instances' attributes. Since both have `name='Alice'`, they evaluate as equal.
Practice tasks
Convert to dataclass
Convert this standard class into a dataclass to remove the boilerplate `__init__` and `__repr__` methods.
Challenge
Dataclass with Defaults
Create a dataclass `Server` with a `host` (str) and a `port` (int). Set the default value of `port` to 80.
Continue learning
Previous: Class Creation and Instantiation
Previous: __init__ and __new__
Previous: __str__ vs __repr__