Cлоты¶
__slots__ позволяет задать ограниченный набор атрибутов, которыми будет обладать экземпляр класса.
Python, как и другие динамические языки (например JavaScript), славен тем, что с объектами и экземплярами в рантайме можно творить практически что угодно — добавлять атрибуты, удалять и изменять их. Это очень удобно и гибко, но всему есть своя цена. И цена здесь - это понижение скорости доступа к аттрибутам и дополнительный расход памяти.
При этом важно понимать, что такое поведение нам нужно не всегда. Бывают случаи, когда мы точно знаем, какие аттрибуты будут у наших экзепляров классов. Или же мы хотим ограничить добавление новых аттрибутов. Именно для этого и существует __slots__
Задание слотов¶
Слоты задаются через аттрибут __slots__ в классе:
class SlotsClass:
__slots__ = ('foo', 'bar')
>>> obj = SlotsClass()
>>> obj.foo = 5
>>> obj.foo
# 5
>>> obj.another_attribute = 'test'
Traceback (most recent call last):
File "python", line 5, in <module>
AttributeError: 'SlotsClass' object has no attribute 'another_attribute'
Теперь мы не можем добавлять аттрибуты в наши объекты. Тем более скорость доступа к аттрибутам повышается на 25-30%, потому что их вычислять теперь не надо.
Экономия памяти¶
При задании __slots__ __dict__ у класса не создается, за счет этого экономится память.
Слабые ссылки¶
По-умолчанию слабые ссылки на экземпляры классов со слотами не работают, по причине того, что ещё перестает создавать аттрибут __weakref__. Решается добавлением __weakref__ в __slots__.
Наследование¶
-
При наследовании класса с
__slots__новый класс конечно унаследует__slots__, но это не помешает созданию__dict__, со всеми вытекающими расходами и фичами:
-
Если мы хотим чтобы
__slots__наследовались нормально и__dict__не создавался, необходимо чтобы классChildSlotsClassтоже реализовал__slots__:class SlotsClass: __slots__ = ('foo', 'bar') class ChildSlotsClass(SlotsClass): __slots__ = ('baz',) >>> obj = ChildSlotsClass() >>> obj.foo = 5 >>> obj.baz = 6 >>> obj.something_new = 3 Traceback (most recent call last): File "python", line 12, in <module> AttributeError: 'ChildSlotsClass' object has no attribute 'something_new' -
За множественное наследование классов у которых есть слоты можно забыть, получим TypeError.