В 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-приложений за счет уменьшения потребления памяти. Тем не менее, его следует использовать с осторожностью, поскольку он имеет ряд ограничений и может сделать ваш код менее гибким.
Содержание: