
В Python все атрибуты объекта хранятся в словаре, доступ к которому осуществляется через специальный атрибут __dict__. Однако, использование словарей не самый эффективный метод хранения данных с точки зрения памяти. Специальный атрибут __slots__ позволяет оптимизировать использование памяти для классов, позволяя зафиксировать множество возможных атрибутов экземпляра.
Атрибут __slots__ объявляется внутри класса и определяет кортеж с именами атрибутов, которые экземпляр класса может иметь.
class MyClass:
__slots__ = ('name', 'age', 'gender')
obj = MyClass()
obj.name = "Alex"
obj.age = 25
obj.gender = "Male"Попытка добавить атрибут, который не определен в __slots__, вызовет ошибку:
obj.height = 180 # вызовет ошибку AttributeError__slots__, являются единственными атрибутами, которые экземпляр класса может иметь. Это значит, что вы не сможете добавить новые атрибуты на лету.__slots__ в производном классе, то вам нужно указать __slots__ и в базовом классе, иначе атрибут __dict__ будет создан, что увеличит использование памяти.__slots__, вы теряете доступ к атрибуту __dict__, поскольку именно этот атрибут __slots__ заменяет. Это означает, что вы не сможете получить список всех атрибутов объекта обычным способом.class MyClass:
__slots__ = ('name', 'age', 'gender')
obj = MyClass()
print(obj.__dict__) # вызовет ошибку AttributeError__slots__ поддерживает только простые строковые имена атрибутов. Это означает, что вы не можете использовать переменные или вычисляемые выражения в качестве имен атрибутов.
attribute_name = 'age'
class MyClass:
__slots__ = (attribute_name) # Это не будет работатьОсновное преимущество использования __slots__ заключается в улучшении эффективности использования памяти. Если у вас есть большое количество объектов с небольшим количеством атрибутов, использование __slots__ может значительно уменьшить объем занимаемой памяти.
Когда вы используете __slots__ в классе, который имеет родительский класс, важно помнить, что __slots__ влияет только на экземпляры того класса, в котором он был объявлен. Если родительский класс не объявил __slots__, у экземпляров дочернего класса все равно будет атрибут __dict__, что может увеличить потребление памяти. Чтобы избежать этого, можно определить __slots__ в родительском классе с пустым значением.
class Parent:
__slots__ = ()
class Child(Parent):
__slots__ = ('name', 'age')
obj = Child()Если вы используете декоратор @property для создания свойств класса, важно знать, что свойства должны быть определены в __slots__, как и любые другие атрибуты.
class MyClass:
__slots__ = ('_x', 'x')
def __init__(self, x):
self._x = x
@property
def x(self):
return self._xПомимо экономии памяти, __slots__ может ускорить доступ к атрибутам, так как поиск атрибута в списке обычно быстрее, чем поиск в словаре. Однако разница в производительности обычно невелика, и в большинстве случаев вы не заметите значительного ускорения.
Атрибут __slots__ является мощным инструментом для контроля атрибутов экземпляров и улучшения производительности Python-приложений за счет уменьшения потребления памяти. Тем не менее, его следует использовать с осторожностью, поскольку он имеет ряд ограничений и может сделать ваш код менее гибким.
Содержание: