Reputation: 848
I have the following Python code snippet.
class LoggedAgeAccess:
def __get__(self, obj, objtype=None):
value = obj._age
return value
def __set__(self, obj, value):
obj._age = value
class Person:
age = LoggedAgeAccess() # Descriptor instance
def __init__(self, name, age):
self.name = name # Regular instance attribute
self.age = age # Calls __set__()
def birthday(self):
self.age += 1 # Calls both __get__() and __set__()
x = Person("ABC", 27)
In the constructor, the second assignment statement self.age = age
triggers the __set__()
method of the LoggedAgeAccess descriptor.
This is really confusing.
When the Person object is created, I am passing name and age values. Inside the constructor, I refer the passed value and create a instance specific variable self.age
whose value is assigned with the passed value (27). How this assignment statement refers the class level age variable and triggers a call to __set__()
?
Upvotes: 0
Views: 52
Reputation: 532093
The key is to recognize that self.age = age
does not unconditionally create an instance attribute named age
on the object self
. Python first checks if self.__dict__['age']
already exists (it does not), if Person.age
exists (it does) and if Person.age
has a __set__
method (it does), and so invokes Person.age.__set__(self, age)
instead of creating an instance attribute.
If self.__dict__['age']
does exist, the value is updated.
If Person.age
was not already defined, then a new instance attribute named age
is created. If Person.age
does exists, but does not have a __set__
method, then a new instance attribute is also created, and that attribute shadows the class attribute with the same name.
Upvotes: 2