Как дата-классы в Python помогают улучшить код?
Что проверяют
Отличаете ли вы @dataclass от «класса с меньшим числом строк» и знаете ли его границы. Обычно следом спрашивают, чем он отличается от NamedTuple, attrs и моделей Pydantic и проверяет ли он типы.
Как отвечать
Модуль dataclasses появился в Python 3.7. Декоратор по аннотациям полей генерирует __init__, __repr__ и __eq__, а по флагам добавляет ещё:
frozen=True: запрет присваивания после создания плюс__hash__, поэтому объект можно класть вsetи использовать как ключ словаря;order=True: методы сравнения<,<=и остальные, сравнение идёт по полям как у кортежа;slots=True(с 3.10):__slots__вместо__dict__, меньше памяти на экземпляр;kw_only=True(с 3.10): поля только именованные, это снимает проблему порядка полей при наследовании;field(default_factory=list): правильный способ задать изменяемое значение по умолчанию;__post_init__: место для вычисляемых полей и проверок.
Полезные функции модуля: replace() для копии с изменёнными полями, asdict() и astuple() для рекурсивного преобразования. Выигрыш для кода в целом: модель данных описана в одном месте, аннотации читают IDE и mypy, объекты сравниваются по значению без ручного __eq__.
Границы тоже назовите. Для данных снаружи (API, конфиг, JSON) с валидацией лучше Pydantic, для неизменяемой записи с доступом по индексу подходит NamedTuple, а attrs даёт больше возможностей при похожем синтаксисе.
Где спотыкаются
Думают, что аннотации проверяются. Если объявить age: int, то User(age="30") создастся без ошибок: дата-класс типы не валидирует, это делают статический анализатор или Pydantic.
Пишут tags: list = []. Дата-класс выбросит ValueError ещё при объявлении класса, нужен field(default_factory=list).
Считают frozen=True полной неизменяемостью. Список внутри замороженного объекта по-прежнему меняется. А при eq=True без frozen класс получает __hash__ = None, и попытка положить объект в set падает с TypeError.