__setattribute__ does not exist, because __setattr__ always called. __getattr__ is only called for fx if the attribute search fails through the regular channel (which is provided by __getattribute__ , so the function is always called as well).
The descriptor protocol is a little orthogonal to others. Considering,
class Foo(object): def __init__(self): self.x = 5 f = Foo()
The following is true:
fx will call f.__getattribute__('x') if it was defined.fx will not invoke f.__getattr__('x') if it were defined.fy will call f.__getattr__('y') if it was defined, otherwise f.__getattribute__('y') if it was defined.
The handle is called by an attribute, not an attribute. I.e:
class MyDescriptor(object): def __get__(...): pass def __set__(...): pass class Foo(object): x = MyDescriptor() f = Foo()
Now fx will call type(f).__dict__['x'].__get__ , and fx = 3 will call type(f).__dict__['x'].__set__(3) .
That is, Foo.__getattr__ and Foo.__getattribute__ will be used to find fx links; as soon as you do this, fx returns the result of type(fx).__get__() , if defined, and fx = y calls fx__set__(y) , if defined.
(The above __get__ and __set__ are only approximately correct, since I did not take into account the details of which arguments __get__ and __set__ really receive, but this should be enough to explain the difference between __get__ and __getattr[ibute]__ .)
Put another way, if MyDescriptor not defined __get__ , then fx will just return an instance of MyDescriptor .
source share