I read a bit on Python's object attribute lookup:
Seems pretty straight forward, so I tried it out (python3):
class A:
def __getattr__(self, attr):
return (1,2,3)
a = A()
a.foobar #returns (1,2,3) as expected
a.__getattribute__('foobar') # raises AttributeError
My question is, aren't the two supposed to be identical?
Why does the second one raise an attribute error?
So apparently the answer is that the logic for a.foobar
IS different from the logic for a.__getattribute("foobar")
. According to the data model: a.foobar
calls a.__getattribute("foobar")
and if it raises an AttributeError, it calls a.-__getattr__('foobar')
So it seems the article has a mistake in their diagram. Is this correct?
And another question: Where does the real logic for a.foobar
sit? I thought it was in __getattribute__
but apparently not entirely.
Edit:
Not a duplicate of Difference between __getattr__ and __getattribute__.
I am asking here what is the different between object.foo
and object.__getattribute__("foo")
.
This is different from __getattr__
vs __getatribute__
which is trivial...
a.__getattribute__('foobar')
toa.__getattr__('foobar')
and see what happens. – Boothman__getattribute__
is supposed to eventually call__getattr__
.a.foobar
is supposed to call__getattribute__
– Latoyialatreece__getattr__
is invoked instead. – Convexitya.foo
is implemented like this:try a.__getattribute__ except AtributeError: a.__getattr__
? – Latoyialatreece__getattr__
is only tried if it exists, and there are special exceptions when magic methods are used. For instance,len
bypasses both__getattribute__
and__getattr__
to retrieve__len__
. – Projection__getattribute__
is a decriptor, defined in one or more base classes (or inobject
if not elsewhere). By default it invokes__getattr__
for unknown (not present in__dict__
or nondefined as__slots__
attrs). So usually you need to redefine__getattr__
to intercept unknown attributes, and__getattribute__
gives you total control (regulary not needed). Something like it – Phosphorite__getattribute__
doesn't invoke__getattr__
; the fallback to__getattr__
is done separately. The fact that this is not__getattribute__
's responsibility is probably the source of the questioner's confusion. – Scopas__getattr__()
, the latter will not be called unless__getattribute__()
either calls it explicitly or raises an AttributeError – Phosphorite__getattribute_
_calling__getattr__
– Latoyialatreece__getattribute__
raises an AttributeError, the attribute lookup process will try__getattr__
next. – Scopas__getattribute__
was in charge of ALL the lookup process... – Latoyialatreece