Зачем нужен атрибут __slots__ в классах Python?
Что проверяют
Понимаете ли вы, что у обычного объекта атрибуты лежат в словаре, и знаете ли цену этой гибкости.
Как отвечать
По умолчанию каждый экземпляр хранит атрибуты в собственном словаре __dict__, поэтому атрибуты можно добавлять на лету. Словарь занимает заметную память, и на миллионе объектов это десятки мегабайт.
__slots__ объявляет фиксированный набор атрибутов. Тогда вместо словаря создаётся компактная структура с заранее известными слотами.
class Point:
__slots__ = ("x", "y")
def __init__(self, x, y):
self.x, self.y = x, y
p = Point(1, 2)
p.z = 3 # AttributeError: атрибута нет в слотахЧто даёт: экономию памяти в разы на большом числе однотипных объектов и чуть более быстрый доступ к атрибутам, потому что нет поиска по словарю. Побочно получается защита от опечаток: присваивание несуществующего атрибута падает сразу, а не создаёт новый тихо.
Ограничения, которые стоит назвать:
- нельзя добавлять атрибуты динамически, включая те, что добавляют некоторые библиотеки;
- слабые ссылки перестают работать, если не добавить
__weakref__в слоты; - при наследовании слоты нужны в каждом классе цепочки, иначе словарь появится снова;
- множественное наследование от двух классов с непустыми слотами запрещено;
- некоторые инструменты, полагающиеся на
__dict__, перестают работать.
Практический совет: в современном коде это чаще всего @dataclass(slots=True), который делает то же самое без ручного перечисления, и применяют его только там, где объектов действительно много.
Где спотыкаются
Добавляют слоты «для скорости» в классы, которых в программе десяток.
Забывают про наследование и не получают экономии вовсе.
Не знают, что слоты ломают присваивание произвольных атрибутов, и потом долго ищут причину падения в чужой библиотеке.