First Example Link to heading
This is write-up based on link for python descriptors.
Descriptors are described as
Descriptors let objects customize attribute lookup, storage, and deletion.
lets start with simplest example
class Age:
def __get__(self, instance, owner):
return instance.age_years * 12
def __set__(self, instance, value):
instance.age_years = value / 12
class Person3:
age_months = Age()
def __init__(self, age):
self.age_years = age
p3 = Person3(2)
print(p3.__dict__)
print(type(p3).__dict__)
print(p3.age_months)
Here age_months
is descriptor that calculates age in month dynamically. age_months is not in __dict__
. but it is in type(Person).__dict__
as 'age_months': <__main__.Age object at 0x7fcbab796970>,
{'age_years': 2}
{'__module__': '__main__', 'age_months': <__main__.Age object at 0x7fcbab796970>, '__init__': <function Person3.__init__ at 0x7fcbab7aa310>, '__dict__': <attribute '__dict__' of 'Person3' objects>, '__weakref__': <attribute '__weakref__' of 'Person3' objects>, '__doc__': None}
24
from SO, the search order as follow:
bar = a.foo…
invokes a.getattribute(‘foo’) which in turn by default looks up a.dict[‘foo’] or invokes foo’s .get() if defined on A. The returned value would then be assigned to bar.
So, in example above, age_months.__get__()
eventually gets called.
other ways to define descriptor Link to heading
Although the pythonic way is using __set__
, __get__
, built-in property
class can be used to create descriptor
class Person1:
def __init__(self, age):
self.age_years = age
def _set_age(self, value):
self.age_years = value/12
def _get_age(self):
return self.age_years * 12
age_months = property(fget=_get_age, fset=_set_age)
p1 = Person1(2)
print(p1.__dict__)
print(type(p1).__dict__)
print(p1.age_months)
Also, there is the decorator @property
class Person2:
def __init__(self, age):
self.age_years = age
@property
def age_months(self):
return self.age_years * 12
@age_months.setter
def age_months(self,value):
self.age_years = value / 12
p2 = Person2(2)
print(p2.__dict__)
print(type(p2).__dict__)
print(p2.age_months)