Декораторы определены для типа объекта, например, в вашем примере для объекта jane
дескриптор, на который ссылается name
, должен быть определен для типа jane
, то есть в теле класса Person
. Таким образом, в случае класса дескриптор должен быть определен в метаклассе класса (поскольку класс является экземпляром его метакласса), чтобы дескриптор вызывался для данного поиска атрибутов в объекте класса.
В вашем примере jane.name
и jane.name = 'Janny'
работали как дескриптор, на который ссылается name
, определяется в теле класса Person
, то есть он существует в Person.__dict__
(который является объектом mappingproxy
и являетсятолько для чтения). Затем Person.name
нашел атрибут в Person.__dict__
и увидел, что у него есть атрибут __get__
, поэтому дескриптор, следовательно, называется __get__
для получения значения. Теперь, когда вы устанавливаете Person.name = 'Jack'
, он устанавливает атрибут name
для ссылки на строковый объект Jack
через Person.__setattr__
, отбрасывая предыдущую ссылку на дескриптор D
. Так что теперь все ссылки на name
, например, если вы сделаете jane.name
/ Person.name
, вы получите строку Jack
.
Вот пример того, как вы можете достичь желаемого поведения с помощьюприменение дескриптора также и к метаклассу:
In [15]: class FooDec:
...: def __get__(self, instance, owner=None):
...: print(f'__get__ called with: instance: {instance}, owner: {owner}')
...: def __set__(self, instance, value):
...: print(f'__set__ called with: instance: {instance}, value: {value}')
...:
In [16]: class Meta(type):
...: foo = FooDec()
...:
In [17]: class People(metaclass=Meta):
...: foo = FooDec()
...:
In [18]: People.foo
__get__ called with: instance: <class '__main__.People'>, owner: <class '__main__.Meta'>
In [19]: People.foo = 100
__set__ called with: instance: <class '__main__.People'>, value: 100
In [20]: p = People()
In [21]: p.foo
__get__ called with: instance: <__main__.People object at 0x7faa0b2cb1c0>, owner: <class '__main__.People'>
In [22]: p.foo = 1
__set__ called with: instance: <__main__.People object at 0x7faa0b2cb1c0>, value: 1