Для чего же нужны __slots__?
Снизить потребление памяти, экземпляром класса, путем ограничения количества поддерживаемых атрибутов.
При использовании __slots__, атрибут __dict__ будет недоступен. Если нужно иметь __dict__, его нужно добавить в __slots__, это будет означать что динамические атрибуты будут работать, тоесть добавляться в словарь __dict__.
Пример:
class A(object):
    """Класс со слотами.
    """
    __slots__ = ('a', 'b', 'c')
Соответственно при попытке доступа в __dict__ получим исключение:
Если добавить __dict__ в слоты
In [1]: a = A()
In [2]: a.__dict__
---------------------------------------------------------
AttributeError        Traceback (most recent call last)
Тогда:
class A(object):
    """Класс со слотами.
    """
    __slots__ = ('a', 'b', 'c', '__dict__')
Не имея атрибута __weakref__, экземпляры классов со __slots__ не поддерживают слабые ссылки на себя. Для поддержки слабых ссылок нужно добавить в перечень атрибутов __weakref__ по тому же принципу как и __dict__.
In [4]: a = A()
In [5]: a.__dict__
Out[5]: {}
In [6]: dir(a)
Out[6]: 
['__class__',
 '__delattr__',
 '__dict__',
 '__doc__',
 '__format__',
 '__getattribute__',
 '__hash__',
 '__init__',
 '__module__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__slots__',
 '__str__',
 '__subclasshook__',
 'a',
 'b',
 'c']
При наследовании от класса со слотами если не объявлены слоты, будет доступен __dict__ соответственно и динамические аттрибуты будут работать. При этом поведение атрибутов объявленых в слотах родительского класса не пеняется.
При наследовании от класса не имеющего __slots__, родителем будет создан __dict__
class A(object):
    """Класс со слотами.
    """
    __slots__ = ('a', 'b', 'c')
class B(A):
    """Класс без слотов, но наследующий класс со слотами.
    """
    pass
In [7]: b = B()
In [8]: dir(b)
Out[8]: 
['__class__',
 '__delattr__',
 '__dict__',
 '__doc__',
 '__format__',
 '__getattribute__',
 '__hash__',
 '__init__',
 '__module__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__slots__',
 '__str__',
 '__subclasshook__',
 '__weakref__',
 'a',
 'b',
 'c']
In [9]: b.__dict__
Out[9]: {}
In [10]: b.a
---------------------------------------------------------
AttributeError        Traceback (most recent call last)
И еще, нельзя определить __slots__ для классов наследующихся от встроенных типов переменной длины, например long, str и tuple. Точнее определить можно, но ненужно :) так как получите исключение TypeError
class C(object):
    """Класс без слотов.
    """
    pass
class D(C):
    """Класс со слотами, но наследующий класс без слотов.
    """
    __slots__ = ('q', 'w', 'e')
In [11]: c = C()
In [12]: d = D()
In [13]: c.__dict__
Out[13]: {}
In [14]: d.__dict__
Out[14]: {}
In [15]: d.__slots__
Out[15]: ('q', 'w', 'e')
In [16]: dir(c)
Out[16]: 
['__class__',
 '__delattr__',
 '__dict__',
 '__doc__',
 '__format__',
 '__getattribute__',
 '__hash__',
 '__init__',
 '__module__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 '__weakref__']
In [17]: dir(d)
Out[17]: 
['__class__',
 '__delattr__',
 '__dict__',
 '__doc__',
 '__format__',
 '__getattribute__',
 '__hash__',
 '__init__',
 '__module__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__slots__',
 '__str__',
 '__subclasshook__',
 '__weakref__',
 'e',
 'q',
 'w']
Русский язык в эпоху глобализации
7 лет назад
 
 
 Сообщения
Сообщения
 
 
Давай с замерами. Сколько это реально сэкономит памяти? И в каких ситуациях есть смысл заморачиваться?
ОтветитьУдалитьХм...
ОтветитьУдалитьДумаю заморочусь на эту тему и замучу сравнение.