namedtuple vs NamedTuple: почему одно содержит __annotations__, а другое — нет

namedtuple vs NamedTuple: почему одно содержит __annotations__, а другое — нет

@python_quiz

Разберем этот квиз

Коротко: небольшой фрагмент кода проверяет наличие атрибута __annotations__ у экземпляров двух похожих структур данных. Результат показывает, что один вариант создаёт аннотации полей, другой — нет. Разберёмся, почему так происходит и что это значит на практике.

Код, который вызывает вопрос

python

Когда вы запускаете этот код, он выведет:

Разбор: как это работает

  • collections.namedtuple создаёт класс на лету, даёт ему удобные имена полей, методы вроде _asdict(), _replace() и т.д. Но он не добавляет атрибут __annotations__ в класс, поскольку не опирается на синтаксис аннотаций типов.
  • typing.NamedTuple — это специальный инструмент для декларации именованных кортежей с использованием синтаксиса аннотаций. При объявлении классов через typing.NamedTuple аннотированные атрибуты попадают в словарь __annotations__ класса.

Важно: проверка производится через hasattr(экземпляр, '__annotations__'). При поиске атрибута на экземпляре Python также смотрит на его класс. Поэтому если класс имеет __annotations__, hasattr(instance, '__annotations__') вернёт True.

Демонстрация свойств и аннотаций

Посмотрим на поведение чуть подробнее:

python

Ожидаемый вывод:

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

  • Если вам важна поддержка аннотаций типов (для статического анализа, автодополнения IDE, сериализации с учётом типов и т.п.), используйте typing.NamedTuple или dataclasses.dataclass.
  • Если нужен просто компактный, быстрый способ определить именованные кортежи без аннотаций — collections.namedtuple остаётся простым и эффективным выбором.
  • Проверка hasattr(instance, '__annotations__') может вернуть True и для экземпляра, если класс имеет это поле — это нормальное поведение механизмов разрешения атрибутов в Python.

Когда выбирать что

  • Нужны аннотации/совместимость с typing — выбирайте typing.NamedTuple или dataclasses (в зависимости от иммутабельности).
  • Нужна совместимость с более старым кодом или минимализм — collections.namedtuple подойдёт.

Надеюсь, краткое сравнение разъяснило, почему в примере один тип возвращает True для __annotations__, а другой — False, и как это влияет на использование в реальных проектах.

Report Page