1

Suppose we define the following python descriptor

class FooDescriptor():
    def __init__(self, name='foo', initval='initval'):
        self.name = name
        self.val = initval

    def __get__(self, instance, cls):
        print("invoke get {} in instance {} in class {}".format(self.name, instance, cls))
        return self.val

    def __set__(self, instance, val):
        print("invoke set {} in instance {}".format(self.name, instance))
        self.val = val

Now if we define the class Foo to have a class attribute of type FooDescriptor and the instance attribute of the same type:

class Foo():
    cdescr = FooDescriptor(name='class attribute descr', initval=1)
    def __init__(self):
        self.idescr = FooDescriptor(name='instance attribute descr', initval=2)

We get the desired behaviour for the class descriptor:

>>> foo = Foo()
>>> foo.cdescr
invoke get class attribute descr in instance <__main__.Foo object at 0x10189ecc0> in class <class '__main__.Foo'>
1
>>> foo.cdescr = 100
invoke set class attribute descr in instance <__main__.Foo object at 0x10189ecc0>
>>> foo.cdescr
invoke get class attribute descr in instance <__main__.Foo object at 0x10189ecc0> in class <class '__main__.Foo'>
100

However for the instance attribute idescr, the descriptor object's __set__ and __get__ methods do not get invoked when attribute is accessed or set:

>>> foo.idescr
<__main__.FooDescriptor object at 0x10189ecf8>
>>> foo.idescr = 120
>>> foo.idescr
120
>>> type(foo.idescr)
<class 'int'>

Any answer for better understanding the scope of the descriptors and how python decides to invoke their __set__ and __get__ when attribute protocal . is seen would be greatly appreciated.

user263387
  • 457
  • 4
  • 5
  • The descriptor protocol won't work on instance attributes. Descriptors are ment to be members of the *class* object, not the instance object – juanpa.arrivillaga Sep 20 '17 at 18:35

1 Answers1

1

That's because descriptors are used when looking up an attribute on the class of an instance. If it's an instance attribute it won't bother with the descriptor protocol.

A good ressource for this kind of question is ionel's blog about metaclasses, which contains this image which also shows when descriptors are used:

enter image description here

(image copied from here)

Because cdescr is in the class.__dict__ and has __get__ and __set__ it will return what the descriptors __get__ returns. However because idescr is not in the class.__dict__ it will simply return what is stored in the instance.__dict__.

MSeifert
  • 145,886
  • 38
  • 333
  • 352