__setattribute__
does not exist because __setattr__
is always called. __getattr__
is only called for f.x
if the attribute lookup fails via the normal channel (which is provided by __getattribute__
, so that function is similarly always called).
The descriptor protocol is slightly orthogonal to the others. Given
class Foo(object):
def __init__(self):
self.x = 5
f = Foo()
The following are true:
f.x
will invoke f.__getattribute__('x')
if __getattribute__
is defined.
f.x
will not invoke f.__getattr__('x')
if __getattr__
is defined.
f.y
will invoke f.__getattr__('y')
if __getattr__
is defined, or else
f.__getattribute__('y')
if __getattribute__
is defined.
The descriptor is invoked by an attribute, rather than for an attribute. That is:
class MyDescriptor(object):
def __get__(...):
pass
def __set__(...):
pass
class Foo(object):
x = MyDescriptor()
f = Foo()
Now, f.x
would cause type(f).__dict__['x'].__get__
to be called, and f.x = 3
would call type(f).__dict__['x'].__set__(3)
.
That is, Foo.__getattr__
and Foo.__getattribute__
would be used to find what f.x
references; once you have that, f.x
produces the result of type(f.x).__get__()
if defined, and f.x = y
invokes f.x.__set__(y)
if defined.
(The above calls to __get__
and __set__
are only approximately correct, since I've left out the details of what arguments __get__
and __set__
actually receive, but this should be enough to explain the difference between __get__
and __getattr[ibute]__
.)
Put yet another way, if MyDescriptor
did not define __get__
, then f.x
would simply return the instance of MyDescriptor
.