__slots__ — специальный атрибут класса, который ограничивает набор допустимых атрибутов экземпляра, экономит память и ускоряет доступ к атрибутам. Использование __slots__ особенно актуально для большого числа однотипных объектов.
История вопроса:
Появление __slots__ связано с тем, что по умолчанию у каждого экземпляра Python-объекта есть словарь атрибутов (__dict__), что удобно, но затратно по памяти. Для миллиона объектов с небольшим набором полей возникает значительный overhead.
Проблема:
Экземпляры обычного класса могут динамически расширяться, что удобно, но неэффективно. Применение __slots__ ограничивает динамическое добавление новых атрибутов, убирает экземплярный словарь атрибутов, экономит память и ускоряет доступ.
Решение:
Описывайте список разрешённых полей в атрибуте __slots__:
class Point: __slots__ = ('x', 'y') def __init__(self, x, y): self.x = x self.y = y p = Point(1, 2) p.z = 3 # AttributeError: 'Point' object has no attribute 'z'
Ключевые особенности:
Можно ли создать экземпляр класса с slots и потом добавить атрибут не из списка?
Нет. При попытке добавить атрибут отсутствующий в списке slots выбросится AttributeError. Это накладывает ограничения на расширяемость объекта.
Можно ли наследовать класс с slots и добавить новые поля?
Да, но каждый наследник должен объявлять свои slots. При этом родительские и текущие slots объединяются. Однако, если не объявить slots в наследнике, у потомка снова появится dict!
Работает ли slots для неизменяемых (immutable) типов?
Да, но надо реализовывать дополнительные меры, чтобы сделать слотовый объект неизменяемым (например, через property без сеттера).
Обычный класс для точки:
class Point: def __init__(self, x, y): self.x = x self.y = y points = [Point(i, i) for i in range(1_000_000)]
Плюсы:
Минусы:
Аналогичный класс, но со слотами:
class Point: __slots__ = ('x', 'y') def __init__(self, x, y): self.x = x self.y = y points = [Point(i, i) for i in range(1_000_000)]
Плюсы:
Минусы: