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