Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are Python descriptor methods not invoked when called with obj.x syntax?

I have a descriptor class X here. I try to use the descriptor X in another class Y

class X:
    def __init__(self, value):
        self.value = value

    def __get__(self, instance, owner):
        print('#### X.__get__ ####')
        return self.value

    def __set__(self, instance, value):
        print('#### X.__set__ ####')
        self.value = value

class Y:
    def __init__(self):
        self.x = X(10)

y = Y()
print(y.x)
y.x = 20

I was hoping that the statement print(y.x) would invoke x.__get__ and the statement y.x = 20 would invoke x.__set__, but it doesn't happen. When I run the above program, I just get this output.

<__main__.X object at 0x7fc65f947950>

Why were the descriptor methods not invoked?

like image 465
Lone Learner Avatar asked Oct 20 '22 18:10

Lone Learner


1 Answers

To get the descriptor protocol methods invoked, you need to put the descriptor instance (X() in your case) on the Y class, not on the instance. This is described in some detail in the Descriptor HowTo Guide by Raymond Hettinger:

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

Note how b.x is transformed into the invocation of the descriptor obtained by dict access of type(b). The Y class should look like this:

class Y:
    x = X(10)

However, since a single instance of X will be shared by all instances of Y, the X descriptor class will need to be modified to get and set the values from instance rather than from self.

like image 109
user4815162342 Avatar answered Oct 22 '22 07:10

user4815162342