Слоты и обобщенные инструмены в Python
ООП на Python слоты python, слоты python пример, слоты python урок
Фактически некоторые экземпляры со слотами вообще могут не иметь атрибут словаря __dict__, что может сделеать некоторые метапрограммы намного более сложными.
Обобщенные инструменты, которые получают списки атрибутов или обращаются к атрибутам, используя имена в виде строк, например, должны использовать более универсальные механизмы, чем атрибут __dict__. К таким механизмам можно отнести встроенные функции getattr, setattr и dir, способные отыскивать атрибуты в обоих хранилищах, __dict__ и __slots__. В некоторых случаях для полноты картины может потребоваться проверить оба источника атрибутов.
Например, экземпляры классов, где используются слоты, обычно не имеют атрибут словаря __dict__ - вместо него пространство для атрибутов в экземпляре выделяется с применением дескрипторов класса.
Только имена, перечисленные в списке __slots__, смогут использоваться как атрибуты экземпляра, однако значения этих атрибутов могут извлекаться и изменяться обычными способами.
class MyClass:
... __slots__ = ['a', 'b'] # По умолчанию наличие __slots__ означает отсутствие __dict__
>>> ZZZ = MyClass()
>>> ZZZ.a = 1
>>> ZZZ.a
1
>>> ZZZ.__dict__
AttributeError: 'ZZZ' object has no attribute '__dict__'
>>> getattr(ZZZ, 'a')
1
>>> setattr(ZZZ, 'b', 10)
>>> ZZZ.b
10
>>> 'a' in dir(ZZZ)
True
>>> 'b' in dir(ZZZ)
True
В отсутствие словаря с пространством имен невозможно присвоить значения атрибутам экземпляра, имена которых отсутствуют в списке слотов:
class MySecondClass:
... __slots__ = ['a', 'b']
... def __init__(self):
... self.d = 4 # Невозможно добавить новый атрибут, когда отсутствует атрибут __dict__
>>> QQQ = MySecondClass()
AttributeError: 'QQQ' object has no attribute 'd'
Однако возможность добавлять новые атрибуты все-таки существует - для этого необходимо включить имя __dict__ в список __slots__, разрешить тем самым создать словарь с пространством имен. В этом случае действовать будут оба механизма хранения имен, однако обобщенные инструменты, такие как getattr, будут воспринимать их, как единое множество атрибутов:
>>> class MyThirdClass:
... __slots__ = ['a', 'b', '__dict__'] # Добавить __dict__ в слоты
... c = 250 # Атрибуты класса действуют как обычно
... def __init__(self):
... self.d = 55 # Имя d будет добавлено в __dict__, а не в __slots__
...
>>> KKK = MyThirdClass()
>>> KKK.d
55
>>> KKK.__dict__ # Некоторые объекты имеют оба атрибута, __dict__ и __slots__
{'d':55} # getattr() может извлекать атрибуты любого типа
>>> KKK.__slots__
['a', 'b', '__dict__']
>>> KKK.c
250
>>> KKK.a # Все атрибуты экземпляра не определены
AttributeError: a # Пока им не будет присвоено значение
>>> KKK.a = 123
>>> KKK.b = 100
>>> getattr(KKK, 'a'), getattr(KKK, 'c'), getattr(KKK, 'd')
(123, 250, 55)
Если потребуется реализовать универсальный способ получения значений всех атрибутов экземпляров, необходимо учесть наличие двух форм хранения атрибутов или использовать функцию dir, которая дополнительно возвращает все унаследованные атрибуты(для получения ключей в следующем примере используется итератор словаря):
>>> for attr in list(KKK.__dict__) + KKK.__slots__:
... print(attr, ' => ', getattr(KKK, attr))
d => 55
a => 123
b => 100
__dict__ => {'d' : 55}
Поскольку любой из этих атрибутов может отсутствовать, более правильный способ выглядит, как показано ниже(функция getattr позволяет определять возвращаемое значение по умолчанию):
>>> for attr in list(getattr(KKK, '__dict__', [])) + getattr(KKK, '__slots__', []):
... print(attr, ' => ', getattr(KKK, attr))
d => 55
a => 123
b => 100
__dict__ => {'d' : 55}
- Множественное наследование в Python
- Доступ к атрибутам класса в языке Python
- Классы нового стиля. ООП в Python
- Альтернативы статическим методам Python
- Абстрактные методы в Python
- Объектно-ориентированное программирование. Методы __init__() и __del__() в Python
- Объектно-ориентированное программирование. Определение класса и создание экземпляра класса в Python