Moving this conversation from python-dev to here because I shouldn't have
sent it to python-dev.

My original message:
I'm working on a large class architecture and I find myself often
overloading __getattr__.  I am continuously running into the issue where I
want __getattr__ to have access to the error that was raised in
__getattribute__, but it seems completely unavailable. Is that true?

What I've learned since then:
There is some weird interplay between __getattribute__, __getattr__, and
python's attribute lookup order which I don't entirely understand.  I've
learned some things from Nick Coghlan and Joao S. O. Bueno, which I'll try
to summarize:

* __getattribute__ does not call __getattr__ within itself; instead,
__getattr__ seems to be called during python's natural attribute lookup
order, but only if an AttributeError is raised during this lookup.
- This has the side effect that calling __getattr__ from __getattribute__
doesn't work properly.

* If __getattr__ is triggered (when an AttributeError is raised during
attribute lookup), it will not have any information about the
AttributeError that triggered it.

* Things may get more complicated if we are doing an attribute lookup on a
property, and an AttributeError is raised within the property's method.
(This is because properties are data descriptors, which complicates
python's natural lookup order.)


Here is the simplest example showing what I mean (there are many more
complicating variations this, and unfortunately I'm running into some of
them):

class A(object):
    def __getattr__(self, attr):
        raise AttributeError("raised from A.__getattr__ to stop execution")

a = A()
print(a.x)

results in:

Traceback (most recent call last):
  File "test.py", line 6, in <module>
    print(a.x)
  File "test.py", line 3, in __getattr__
    raise AttributeError("raised from A.__getattr__ to stop execution")
AttributeError: raised from A.__getattr__ to stop execution

The thing to note here is that the AttributeError on the normal
__getattribute__'s lookup isn't in the stack trace.  That error is:
Traceback (most recent call last):
  File "test2.py", line 35, in <module>
    print(a.x)
AttributeError: 'A' object has no attribute 'x'

-- that last line, "AttributeError: 'A' object has no attribute 'x'" does
not appear in the stack trace for my above example (because __getattr__ is
implemented).  This is because in python's attribute lookup order,
__getattr__ is called if an AttributeError is raised, and that raised
AttributeError gets completely discarded.

So basically I want access to the intermediate AttributeError that caused
__getattr__ to be raised in the first place.


This is complicated, and I may have explained something poorly. If so,
please don't hesitate to ask for more explanation or examples.  This is
already long, so I'll stop typing now.

Thanks,
Jason
-- 
https://mail.python.org/mailman/listinfo/python-list

Reply via email to