Why does the __get__
method in a python descriptor accept the owner class as it's third argument? Can you give an example of it's use?
The first argument (self
) is self evident, the second (instances
) makes sense in the context of the typically shown descriptor pattern (ex to follow), but I've never really seen the third (owner
) used. Can someone explain what the use case is for it?
Just by way of reference and facilitating answers this is the typical use of descriptors I've seen:
class Container(object):
class ExampleDescriptor(object):
def __get__(self, instance, owner):
return instance._name
def __set__(self, instance, value):
instance._name = value
managed_attr = ExampleDescriptor()
Given that instance.__class__
is available all I can think of is that explicitly passing the class has something to do with directly accessing the descriptor from the class instead of an instances (ex Container.managed_attr
). Even so I'm not clear on what one would do in __get__
in this situation.
Python's __get__() magic method defines the dynamic return value when accessing a specific instance and class attribute. It is defined in the attribute's class and not in the class holding the attribute (= the owner class).
Python descriptors are created to manage the attributes of different classes which use the object as reference. In descriptors we used three different methods that are __getters__() , __setters__() , and __delete__() . If any of those methods are defined for an object, it can be termed as a descriptor.
Descriptors are Python objects that implement a method of the descriptor protocol, which gives you the ability to create objects that have special behavior when they're accessed as attributes of other objects.
owner - this refers to the class where the descriptor object was created, remember descriptor objects are defined at class level. instance - this refers to the object of the class owner where you defined the descriptor object.
owner
is used when the attribute is accessed from the class instead of an instance of the class, in which case instance
will be None
.
In your example attempting something like print(Container.managed_attr)
would fail because instance
is None
so instance._name
would raise an AttributeError
.
You could improve this behavior by checking to see if instance is None
, and it may be useful for logging or raising a more helpful exception to know which class the descriptor belongs to, hence the owner
attribute. For example:
def __get__(self, instance, owner):
if instance is None:
# special handling for Customer.managed_attr
else:
return instance._name
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With