Что такое __slots__ в Python и для чего он используется?
Что проверяют
Понимаете ли вы, что экономится, и знаете ли ограничения.
Как отвечать
Обычно каждый экземпляр хранит атрибуты в собственном словаре, что и позволяет добавлять их динамически. Объявление фиксированного набора атрибутов отменяет этот словарь: под атрибуты выделяются заранее известные ячейки, как в структуре.
class Point:
__slots__ = ("x", "y")
def __init__(self, x, y):
self.x = x
self.y = yЧто это даёт:
- экономия памяти, и она значительная. Словарь на каждый экземпляр стоит сотни байт, поэтому на миллионах мелких объектов разница измеряется сотнями мегабайт. Это основная причина применения;
- немного более быстрый доступ к атрибутам, потому что вместо поиска в словаре идёт обращение по фиксированному смещению;
- защита от опечаток: присваивание несуществующего атрибута даёт ошибку сразу, а не создаёт молча новое поле. Побочный, но приятный эффект.
Ограничения:
- нельзя добавить атрибут динамически. Ради этого всё и затевалось, но иногда это ломает библиотеки, ожидающие возможность что-то дописать в объект;
- пропадает и слабая ссылка: если она нужна, её добавляют в набор явно;
- наследование требует внимания. Если наследник не объявит свой набор, у него появится обычный словарь, и вся экономия исчезнет. При этом повторять в наследнике атрибуты родителя не следует: получатся дублирующие ячейки;
- множественное наследование от двух классов с непустыми наборами невозможно;
- атрибуты класса с теми же именами конфликтуют с объявленными ячейками.
Современная альтернатива: классы данных умеют включать этот механизм параметром, и это самый удобный способ получить и краткость объявления, и экономию.
Практический совет: применять осознанно, когда объектов действительно очень много. Для десятка экземпляров смысла нет.
Где спотыкаются
Применяют механизм везде подряд ради мнимой оптимизации.
Забывают объявить набор в наследнике и теряют экономию.
Дублируют атрибуты родителя в наследнике.
Не учитывают, что пропадает возможность слабой ссылки.