Eric Snow added the comment:
Got bit by a variation of this today in 2.7:
class Spam(object):
def __getattr__(self, attr):
raise AttributeError(attr)
@property
def eggs(self):
return self.ham
s = Spam()
s.eggs
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __getattr__
AttributeError: eggs
It took me a little while to figure out what was going on. A real
head-scratcher. This is because the AttributeError was attributed to the
property, but was actually caused by the __getattr__ call triggered by the
property's code. I would expect the AttributeError to reference "ham", not
"eggs". As already noted, if __getattr__() is not there, that's what happens.
Regardless, I'm just not seeing where the hurdle is to improving this behavior.
I certainly agree that this is not a feature. It is the source of very
mysterious failures.
I was surprised that AttributeError does not have an attribute to which the
name would be bound. If it did, then slot_tp_getattr_hook() could check
against that:
if (res == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyObject *tp, *exc, *tb, *exc_attr;
PyErr_Fetch(&tp, &exc, &tb);
exc_attr = PyObject_GetAttrString(exc, "attribute");
PyErr_Restore(tp, exc, tb);
if (!exc_attr || exc_attr == name) {
PyErr_Clear();
res = call_attribute(self, getattr, name);
}
Py_XDECREF(exc_attr);
}
Alternatively, when an AttributeError comes out of a getter in
_PyObject_GenericSetAttrWithDict() (in either spot they're called), another
exception (not AttributeError) could be raised with the original chained onto
it. Then slot_tp_getattr_hook() won't silently ignore it. It would be
something like this:
if (f != NULL && PyDescr_IsData(descr)) {
res = f(descr, obj, value);
if (!res && PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyObject *msg = PyUnicode_FromFormat("getter failed for '%U'",
name);
/* implicit chaining here */
PyErr_SetObject(PyExc_???Error, msg);
}
goto done;
}
Conceptually, it's as though locating the attribute and extracting the value
are lumped together here. Distinguishing the two would help make this failure
situation much less confusing.
Additionally, it would be really helpful to have a brief mention of this
behavior (AttributeErrors in getters falling back to __getattr__) in the
language reference entry for __getattr__ and/or descriptors.
----------
nosy: +eric.snow
versions: +Python 3.4
_______________________________________
Python tracker <[email protected]>
<http://bugs.python.org/issue1615>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com