Reputation: 3218
I am trying to understand descriptors in Python. What I can't seem to get my head around is what is the instance and owner in the descriptor method:
object.__get__(self, instance, owner)
Now I have read the documentation saying that:
owner is always the owner class, while instance is the instance that the attribute was accessed through, or None when the attribute is accessed through the owner.
Unfortuanately I am having trouble understanding what that means. Does owner refer to the class itself? The class object? Then what is the purpose of instance being passed to it?
Upvotes: 4
Views: 2248
Reputation: 4158
Consider this
__get__(self, instance, owner):
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.
The purpose of passing the instance
to the __get__
method of the descriptor is to make sure we know and identify from which object of the owner
class you are accessing the descriptor instance.
Since descriptor objects are created at the class level, so a naive implementation of the descriptor class itself can result in having multiple objects of the owner
class overriding the value of descriptor instance. Here is an example of such code
def __get__(self, instance, owner):
return self.data
def __set__(self, instance, data):
if value < 1:
raise Exception("Negative or zero is not allowed")
else:
self.data = value
So in the above example the value of data
is stored inside the descriptor instance only and this code will have serious side effects, if you are creating multiple objects of the owner
class and let's say these objects are setting the value of data
.
So in order to solve such a problem you would need to store the value of data
in __dict__
of instance
but how would you that if you don't have access to instance
in the descriptor class itself ?? So as per my experience this is the primary purpose of having instance
in the descriptor class. As a reference for solving the above mentioned problem and putting the instance
in use, here is the code
class DataDescriptor(object):
def __init__(self, attribute):
self.default = 100
self.attribute = attribute
def __get__(self, instance, owner):
print('Getting the value of', self.attribute,
'__get__ of Data descriptor invoked')
return instance.__dict__.get(self.attribute, self.default)
def __set__(self, instance, value=200):
if value > 0:
print('__set__ of Data descriptor invoked')
instance.__dict__[self.attribute] = value
else:
sys.exit('Negative value not allowed')
Upvotes: 1
Reputation: 4209
The relationships can be illustrated by this code:
class DescriptorClass:
def __get__(self, instance, owner):
return self, instance, owner
class OwnerClass:
descr = DescriptorClass()
ownerinstance = OwnerClass()
self, instance, owner = ownerinstance.descr
assert self is OwnerClass.__dict__['descr']
assert instance is ownerinstance
assert owner is OwnerClass
self, instance, owner = OwnerClass.descr
assert instance is None
Upvotes: 4
Reputation: 77892
Does owner refer to the class itself?
Yes.
The class object?
This is the exact same thing.
Then what is the purpose of instance being passed to it?
How would the descriptor access the instance it's been looked up on else ? If you take the builtin property
type for example, it works by storing accessor functions and calling back on those functions. Those functions expect the current instance as first argument (canonically named "self"). If the descriptor doesn't get the current instance, it obviously cannot pass it to the accessor.
Upvotes: 2