Given:
In [37]: class A:
....: f = 1
....:
In [38]: class B(A):
....: pass
....:
In [39]: getattr(B, 'f')
Out[39]: 1
Okay, that either calls super or crawls the mro?
In [40]: getattr(A, 'f')
Out[40]: 1
This is expected.
In [41]: object.__getattribute__(A, 'f')
Out[41]: 1
In [42]: object.__getattribute__(B, 'f')
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-42-de76df798d1d> in <module>()
----> 1 object.__getattribute__(B, 'f')
AttributeError: 'type' object has no attribute 'f'
What is getattribute not doing that getattr does?
In [43]: type.__getattribute__(B, 'f')
Out[43]: 1
What?! type.__getattribute__
calls super but object
's version doesn't?
In [44]: type.__getattribute__(A, 'f')
Out[44]: 1
You are operating directly on classes.
object.__getattribute__
is only used on instances ofA
andB
instead. That's because special methods are looked up on the type; for instances the type is the class.For classes then, the type is..
type
:so
type.__getattribute__
is used:and
object.__getattribute__
works fine on instances:For instances attributes are looked up first on the class (in the case of data descriptors), then on the instance, then if the instance doesn't have the attribute, the class hierarchy is searched in MRO order. This is the job of
object.__getattribute__
. Soobject.__getattribute__
looks at the first argument (e.g.self
, the instance object) for the attribute, and at objects intype(self).__mro__
.For classes, attributes are looked up on the class itself and all its bases;
type.__getattribute__
looks directly atself.__mro__
for these;self
being a class object here.If you use
object.__getattribute__
for classes then, there is nof
attribute onB
directly, and nof
anywhere intype(B).__mro__
. If you usetype.__getattribute__
,A
is a member ofB.__mro__
sof
is found there: