diff options
author | Benjamin Peterson <benjamin@python.org> | 2008-11-17 22:45:50 (GMT) |
---|---|---|
committer | Benjamin Peterson <benjamin@python.org> | 2008-11-17 22:45:50 (GMT) |
commit | 9262b849fba5cb6930a59114cdd6f95ad2847abb (patch) | |
tree | ed344f20374c141944dea26d6082a118bca5a7ca /Objects | |
parent | ce0506ced3f04e751eb841111b43ce9c29fcdd07 (diff) | |
download | cpython-9262b849fba5cb6930a59114cdd6f95ad2847abb.zip cpython-9262b849fba5cb6930a59114cdd6f95ad2847abb.tar.gz cpython-9262b849fba5cb6930a59114cdd6f95ad2847abb.tar.bz2 |
Merged revisions 67246 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
r67246 | benjamin.peterson | 2008-11-17 16:39:09 -0600 (Mon, 17 Nov 2008) | 5 lines
when __getattr__ is a descriptor, call it correctly; fixes #4230
patch from Ziga Seilnacht
........
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/typeobject.c | 39 |
1 files changed, 36 insertions, 3 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 7f9551f..7f9a26d 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4960,6 +4960,24 @@ slot_tp_getattro(PyObject *self, PyObject *name) } static PyObject * +call_attribute(PyObject *self, PyObject *attr, PyObject *name) +{ + PyObject *res, *descr = NULL; + descrgetfunc f = Py_TYPE(attr)->tp_descr_get; + + if (f != NULL) { + descr = f(attr, self, (PyObject *)(Py_TYPE(self))); + if (descr == NULL) + return NULL; + else + attr = descr; + } + res = PyObject_CallFunctionObjArgs(attr, name, NULL); + Py_XDECREF(descr); + return res; +} + +static PyObject * slot_tp_getattr_hook(PyObject *self, PyObject *name) { PyTypeObject *tp = Py_TYPE(self); @@ -4978,24 +4996,39 @@ slot_tp_getattr_hook(PyObject *self, PyObject *name) if (getattribute_str == NULL) return NULL; } + /* speed hack: we could use lookup_maybe, but that would resolve the + method fully for each attribute lookup for classes with + __getattr__, even when the attribute is present. So we use + _PyType_Lookup and create the method only when needed, with + call_attribute. */ getattr = _PyType_Lookup(tp, getattr_str); if (getattr == NULL) { /* No __getattr__ hook: use a simpler dispatcher */ tp->tp_getattro = slot_tp_getattro; return slot_tp_getattro(self, name); } + Py_INCREF(getattr); + /* speed hack: we could use lookup_maybe, but that would resolve the + method fully for each attribute lookup for classes with + __getattr__, even when self has the default __getattribute__ + method. So we use _PyType_Lookup and create the method only when + needed, with call_attribute. */ getattribute = _PyType_Lookup(tp, getattribute_str); if (getattribute == NULL || (Py_TYPE(getattribute) == &PyWrapperDescr_Type && ((PyWrapperDescrObject *)getattribute)->d_wrapped == (void *)PyObject_GenericGetAttr)) res = PyObject_GenericGetAttr(self, name); - else - res = PyObject_CallFunctionObjArgs(getattribute, self, name, NULL); + else { + Py_INCREF(getattribute); + res = call_attribute(self, getattribute, name); + Py_DECREF(getattribute); + } if (res == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_Clear(); - res = PyObject_CallFunctionObjArgs(getattr, self, name, NULL); + res = call_attribute(self, getattr, name); } + Py_DECREF(getattr); return res; } |