Как ответить
Слоты (__slots__) — это механизм, который позволяет явно зафиксировать набор атрибутов экземпляра класса. По умолчанию каждый объект Python хранит свои поля в динамическом словаре __dict__, что даёт гибкость, но расходует память (типичный объект с парой полей — ~50–100 байт на служебную структуру). Если у класса сотни тысяч экземпляров, __slots__ может сократить потребление памяти в 2–5 раз.
Я использую слоты в проектах, где критична память или скорость доступа к атрибутам. Пример из продакшена: парсинг логов в реальном времени. У нас были объекты LogEntry с 6–8 полями, и на обработку 10 миллионов записей слоты снизили потребление памяти с 800 МБ до ~200 МБ. Код выглядел так:
class LogEntry:
__slots__ = ('timestamp', 'level', 'logger', 'message', 'extra')
def __init__(self, timestamp, level, logger, message, extra=None):
self.timestamp = timestamp
self.level = level
self.logger = logger
self.message = message
self.extra = extra
Помимо экономии памяти, слоты дают более быстрый доступ к атрибутам (поиск по фиксированному слоту вместо хэш-таблицы). В моих тестах это ускорило чтение на 10–15% на горячем пути.
Но есть нюансы, которые нужно учитывать:
- Наследование: если родительский класс не определяет
__slots__, у потомка всё равно появится__dict__. Нужно явно прописывать слоты в каждом классе иерархии, включая родительский. - Совместимость с дескрипторами: слоты не работают с обычным наследованием дескрипторов (например,
@property). Если в слоте объявлено имя, его нельзя повторно определить как свойство — получите ошибкуAttributeError. - Множественное наследование: если несколько родительских классов имеют разные слоты, их нужно объединить вручную. Python не делает этого автоматически.
- Динамические атрибуты: раз нет
__dict__, нельзя добавлять новые поля вне списка слотов без специального трюка (например, включив'__dict__'в__slots__). - Weak references: объекты со слотами по умолчанию не поддерживают слабые ссылки; если нужно — добавьте
'__weakref__'в__slots__.
В типовых бизнес-задачах с единичными экземплярами слоты избыточны. Я применяю их в трёх случаях: высоконагруженные модели данных (логи, сущности в игровых движках), в библиотеках для машинного обучения, где десятки тысяч объектов, и в PyPy — там слоты дополнительно оптимизируются JIT-компилятором.
Также стоит помнить, что __slots__ можно комбинировать с dataclasses через параметр slots=True (Python 3.10+). Это удобно: @dataclass(slots=True) автоматически создаёт слоты, избавляя от ручного объявления. При этом сохраняются все преимущества датаклассов (генерация __init__, __repr__ и т.д.) и слотовая оптимизация. На практике это часто лучший компромисс.