Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
Принимая во внимание концепцию Питона, что все открыто для всех, почему бы не сделать доступ к «классным» атрибутам только через __class__ или его аналог.
Drum.__class__. vtypeIowa = Vessel("Iowa")
Drum=Vessel("Drum")
printAttr(Iowa, Drum)iowa = Vessel("Iowa")
drum = Vessel("Drum")
print_attr(Iowa, Drum)изменения значения атрибута у всех инстансов, как это происходит при обращении через __class__
class x():
prop=1
class y(x):
pass
inst = y()
inst.prop = 555
inst.__class__.prop = 666Обычное перекрытие свойств класса свойствами объекта.
причем не описанная в документации.
Class instances
A class instance is created by calling a class object (see above). A class instance has a namespace implemented as a dictionary which is the first place in which attribute references are searched. When an attribute is not found there, and the instance’s class has an attribute by that name, the search continues with the class attributes. If a class attribute is found that is a user-defined function object, it is transformed into an instance method object whose __self__ attribute is the instance. Static method and class method objects are also transformed; see above under “Classes”. See section Implementing Descriptors for another way in which attributes of a class retrieved via its instances may differ from the objects actually stored in the class’s __dict__. If no class attribute is found, and the object’s class has a __getattr__() method, that is called to satisfy the lookup.
Attribute assignments and deletions update the instance’s dictionary, never a class’s dictionary. If the class has a __setattr__() or __delattr__() method, this is called instead of updating the instance dictionary directly.
Class instances can pretend to be numbers, sequences, or mappings if they have methods with certain special names. See section Special method names.
Special attributes: __dict__ is the attribute dictionary; __class__ is the instance’s class.
If the class has a __setattr__() or __delattr__() method, this is called instead of updating the instance dictionary directly.
В документации как раз чёрным по белому написано, что любые присваивания атрибутам всегда идут в экземпляр (если это не атрибут-дескриптор, в котором вы можете реализовать любую логику).
Читаем абзац из раздела 7.2 Инструкции присваивания «Справочного руководства по языку Python» (выделено жирным моё):
7.2 Инструкции присваивания
…
Присваивание объекта одной цели рекурсивно определяется следующим образом.
…
- Если целью является ссылка на атрибут: в ссылке вычисляется первичное выражение. Оно должно выдать объект с присваиваемыми атрибутами; если это не так, возбуждается исключение
TypeError. Затем этому объекту предлагается присвоить данному атрибуту присваиваемый объект; если он не может выполнить присваивание, он возбуждает исключение (обычно, но не обязательно,AttributeError).
Примечание: Если объект является экземпляром класса и ссылка на атрибут появляется с обеих сторон оператора присваивания, выражение справа,a.x, может получить доступ к атрибуту экземпляра или (если атрибут экземпляра не существует) к атрибуту класса. Цель слеваa.xвсегда устанавливается в атрибут экземпляра, при необходимости создавая его. Таким образом, два вхожденияa.xне обязательно ссылаются на один и тот же атрибут: если выражение справа ссылается на атрибут класса, выражение слева создаёт новый атрибут экземпляра в качестве цели присваивания:
class Cls: x = 3 # переменная класса inst = Cls() inst.x = inst.x + 1 # записывает 4 в inst.x, оставляя Cls.x равным 3
Это описание не обязано применяться к атрибутам-дескрипторам, вроде свойств, созданных с помощьюproperty().
...
Если начать разбираться с namespace-ами, то подобное поведение становится понятным.
Однако для программистов, кто раньше работал с нормальными языками, это по меньшей мере кажется странным.
Метаморфозы атрибутов класса