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.