Короткий ответ
__slots__ объявляет фиксированный набор атрибутов экземпляра, запрещая создание обычного __dict__ для каждого объекта — это экономит память, особенно при создании большого числа объектов.
Как это работает подробнее
Без __slots__ каждый экземпляр по умолчанию хранит свой __dict__ для произвольных атрибутов, что добавляет накладные расходы памяти. С __slots__ = ("a", "b") Python выделяет компактные слоты фиксированного размера вместо словаря, а попытка установить неуказанный атрибут вызовет AttributeError.
Пример кода
example-270.py
import sys
class PointDict:
def __init__(self, x, y):
self.x = x
self.y = y
class PointSlots:
__slots__ = ("x", "y")
def __init__(self, x, y):
self.x = x
self.y = y
pd, ps = PointDict(1, 2), PointSlots(1, 2)
print(sys.getsizeof(pd.__dict__)) # есть отдельный словарь атрибутов
try:
ps.z = 3 # AttributeError: объект PointSlots не поддерживает новые атрибуты
except AttributeError as e:
print(e)Что использовать на практике
- Практика.
__slots__особенно выгоден для классов, которых создаётся очень много экземпляров (узлы структуры данных, DTO-объекты в горячем пути) — экономия памяти на миллионах объектов может быть значительной; также слегка ускоряет доступ к атрибутам.
Подводные камни
- Риски. Забывают, что
__slots__не наследуется «бесплатно» — если хотя бы один класс в цепочке наследования не объявляет__slots__, экземпляры всё равно получат__dict__; пытаются динамически добавлять новые атрибуты к объекту со__slots__и получаютAttributeError.