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