Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding Python Descriptors

I am trying to understand descriptors better.

I don't understand why in the foo method the descriptors __get__ method doesn't get called.

As far as I understand descriptors the __get__ method always get called when I access the objects attribute via dot operator or when I use __getattribute__().

According to the Python documentation:

class RevealAccess(object):
    def __init__(self, initval=None, name='var'):
        self.val = initval
        self.name = name

    def __get__(self, obj, objtype):
        print('Retrieving', self.name)
        return self.val

    def __set__(self, obj, val):
        print('Updating', self.name)
        self.val = val

class MyClass(object):
    x = RevealAccess(10, 'var "x"')
    y = 5

    def foo(self):
        self.z = RevealAccess(13, 'var "z"')
        self.__getattribute__('z')
        print(self.z)

m = MyClass()
m.foo()
m.z # no print
m.x # prints var x
like image 785
GarlicPasta Avatar asked Apr 28 '15 20:04

GarlicPasta


1 Answers

z is an attribute on the instance, not on the class. The descriptor protocol only applies to attributes retrieved from a class.

From the Descriptor HOWTO:

For objects, the machinery is in object.__getattribute__() which transforms b.x into type(b).__dict__['x'].__get__(b, type(b)).

and in the Implementing Descriptors section of the Python Data Model:

The following methods only apply when an instance of the class containing the method (a so-called descriptor class) appears in an owner class (the descriptor must be in either the owner’s class dictionary or in the class dictionary for one of its parents).

Your m.z cannot be found in the class dict; type(m).__dict__['z'] does not exist; it is found in m.__dict__['z'] instead. Here m is the instance and the owner class is MyClass, and z does not appear in the owner class dictionary.

like image 130
Martijn Pieters Avatar answered Oct 28 '22 12:10

Martijn Pieters