Декоратор @dataclass — один из инструментов, введённых в Python 3.7 для сокращения шаблонного кода при создании простых классов хранения данных. Благодаря аннотациям типов Python сам автоматически создает методы __init__, __repr__, __eq__ и другие.
История вопроса:
До появления dataclass разработчики писали шаблонные классы вручную, реализуя конструкторы, методы сравнения, repr, а после часто переходили на именованные кортежи или библиотеки типа attrs. Введение @dataclass стандартизировало и упростило этот процесс.
Проблема:
Шаблонный код (boilerplate), дублирование кода конструкторов и методов сравнения часто приводят к ошибкам и усложняли поддержку крупных приложений.
Решение:
Использование аннотаций типов и специального декоратора @dataclass позволяет автоматически сгенерировать все нужные методы в классе.
Пример кода:
from dataclasses import dataclass @dataclass class Point: x: int y: int p1 = Point(10, 20) p2 = Point(10, 20) print(p1 == p2) # True, автоматически сгенерирован __eq__ print(p1) # Point(x=10, y=20), автоматически сгенерирован __repr__
Ключевые особенности:
Изменяет ли @dataclass поведение наследования (особенности при наследовании)?
Да. При наследовании классов dataclass особое внимание: поля базового класса идут раньше, чем поля дочернего, также могут возникать ошибки при конфликте конструкторов/порядка аргументов. Если в базовом и дочернем разных полях одинаковые имена, последний перекроет предыдущий.
Можно ли в dataclass использовать изменяемые значения по умолчанию для полей?
Нет, напрямую использовать такие объекты (например, список) как дефолт нельзя — надо использовать field(default_factory=list). Иначе все экземпляры класса будут разделять одну и ту же коллекцию.
Пример:
from dataclasses import dataclass, field @dataclass class User: values: list = field(default_factory=list)
Является ли @dataclass быстрым для любых сценариев? Подходит ли он для оптимального хранения больших массивов данных?
Нет. dataclass — не самый эффективный для оптимизации памяти вариант. Для хранения миллионов объектов лучше использовать __slots__, namedtuple или специальные структуры — dataclass добавляет служебные поля и не экономит память как слоты. Можно комбинировать, передав параметр slots=True (Python 3.10+), либо вручную использовать slots.
@dataclass class Cart: items: list = [] # ошибка! c1 = Cart() c2 = Cart() c1.items.append("a") print(c2.items) # ['a'] — все Cart разделяют один список
Плюсы:
Минусы:
from dataclasses import dataclass, field @dataclass class Cart: items: list = field(default_factory=list) c1 = Cart() c2 = Cart() c1.items.append("a") print(c2.items) # []
Плюсы:
Минусы:
field(default_factory=...) (что требует отдельного изучения).