Урок курса

Dataclass, NamedTuple или обычный класс в Python

Python для продвинутых: ООП, типизация и тестирование

@dataclass генерирует служебные методы для класса, описанного аннотациями: обычно __init__, __repr__ и __eq__. Это уменьшает шаблонный код, но оставляет полноценный класс с методами и явным поведением.

from dataclasses import dataclass

@dataclass(frozen=True, slots=True)
class Point:
    x: float
    y: float

    def distance_squared(self) -> float:
        return self.x ** 2 + self.y ** 2

frozen=True запрещает обычное изменение полей после создания, а slots=True может уменьшить память и запретить случайные новые атрибуты. Это настройки контракта, а не универсальные ускорители.

Чем отличается NamedTuple

typing.NamedTuple создаёт неизменяемый tuple-подобный объект с именованными полями. Он поддерживает распаковку и индексацию, поэтому удобен на границе со старым кодом, ожидающим кортеж. Но tuple-семантика иногда вредна: два разных типа NamedTuple с одинаковыми значениями могут сравниваться как равные последовательности.

Обычный класс лучше, когда создание объекта должно строго проверять инварианты, есть сложное наследование или публичный конструктор не совпадает с набором хранимых полей. Dataclass тоже поддерживает __post_init__, но не стоит превращать его в скрытую фабрику со множеством побочных эффектов.

Словарь остаётся подходящим для действительно динамической схемы. Если набор ключей стабилен и значим для домена, отдельный тип обычно улучшает подсказки IDE и рефакторинг.

Практический выбор

Используйте dataclass для внутренних value objects и DTO, когда поля известны, нужны понятный repr и сравнение. Используйте frozen dataclass для значений, которые не должны меняться после создания. NamedTuple уместен для компактной неизменяемой записи с необходимой совместимостью с tuple.

Аннотации dataclass сами по себе не валидируют типы во время выполнения. Передача строки в поле float не вызовет автоматическую ошибку. Для внешнего недоверенного ввода нужен отдельный валидатор или модель данных с runtime-проверкой.

Не выбирайте структуру только по числу строк кода. Важнее семантика: можно ли менять объект, должен ли он быть hashable, нужна ли tuple-совместимость и где проверяются инварианты.

Попробуйте решить

Что @dataclass делает с аннотациями типов по умолчанию?

Продолжить с проверкой и прогрессом

Откройте интерактивный раннер с заданиями урока.

Перейти к интерактивному уроку