Что такое __slots__ и как это влияет на производительность?

__slots__ отключает для экземпляров класса обычный словарь атрибутов __dict__ и заранее фиксирует набор полей, что уменьшает накладные расходы на объект (память, иногда скорость доступа к атрибутам), но ограничивает динамическое добавление атрибутов и усложняет наследование.
Подробный ответ

Что делает __slots__ технически

По умолчанию у экземпляра пользовательского класса есть словарь __dict__, где хранятся все его атрибуты. Это даёт гибкость, но стоит памяти и косвенного обращения через хеш‑таблицу.

Если в классе объявить __slots__, интерпретатор:

  • перестаёт создавать __dict__ для экземпляров (если его явно не включили в __slots__);

  • выделяет для каждого имени в __slots__ фиксированное место в структуре объекта (как поля в C‑структуре).

class Point:
   __slots__ = ("x", "y")
   def __init__(self, x, y):
       self.x = x
       self.y = y

Экземпляр Point будет занимать меньше памяти, чем аналогичный класс без __slots__, и не позволит динамически добавить новый атрибут (p.z = ... приведёт к AttributeError).

Влияние на производительность

  • Память: для большого числа однотипных объектов экономия может быть существенной (десятки процентов на экземпляр), особенно если в объекте всего несколько полей.

  • Скорость: доступ к атрибуту через фиксированный offset обычно немного быстрее, чем через словарь; выигрыш небольшой, но на горячих путях может быть заметен.

Ограничения и подводные камни

  • нельзя добавлять произвольные атрибуты, не указанные в __slots__ (если не включить "__dict__" в список слотов);

  • слоты и наследование: при сложной иерархии важно аккуратно проектировать __slots__ в базах и наследниках, объединять их и помнить, что слоты не наследуются «автоматически» как ожидают многие;

  • если нужны weakref’ы, нужно явно добавить "__weakref__" в __slots__;

  • в обычном бизнес‑коде для десятков объектов выгода зачастую не оправдывает усложнение модели классов.

Когда __slots__ уместен

  • массовые структуры: миллионы однотипных объектов (DTO, ноды AST, элементы графа, внутренние структуры в высоконагруженном коде);

  • слои, где важно жёстко фиксировать API объекта и не допускать динамических атрибутов (раннее выявление опечаток/ошибок);

  • в сочетании с dataclasses (slots=True), где генерация кода и слотов берётся на себя стандартной библиотекой.

Формулировка уровня senior

__slots__ — это способ сказать интерпретатору: «экземпляры этого класса имеют фиксированный набор полей, словарь атрибутов им не нужен». Это уменьшает память и иногда ускоряет доступ к атрибутам, но усложняет наследование и лишает гибкости динамических атрибутов. В продакшене я применяю __slots__ точечно — в горячих местах и массовых структурах, чаще через @dataclass(slots=True), чем руками.

Оцени свой прогресс

Честно оцени своё понимание этого вопроса, чтобы мы могли построить твой учебный трек максимально эффективно.
Читать в блоге