mirror of https://github.com/python/cpython
gh-102213: Optimize the performance of `__getattr__` (GH-103761)
Co-authored-by: Kirill <80244920+Eclips4@users.noreply.github.com> Co-authored-by: Łukasz Langa <lukasz@langa.pl> Co-authored-by: Xiang Wang <34048878+wangxiang-hz@users.noreply.github.com>
This commit is contained in:
parent
487f55d580
commit
59c27fa5cb
|
@ -5004,7 +5004,7 @@ order (MRO) for bases """
|
||||||
self.assertEqual(Parent.__subclasses__(), [])
|
self.assertEqual(Parent.__subclasses__(), [])
|
||||||
|
|
||||||
def test_attr_raise_through_property(self):
|
def test_attr_raise_through_property(self):
|
||||||
# add test case for gh-103272
|
# test case for gh-103272
|
||||||
class A:
|
class A:
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
raise ValueError("FOO")
|
raise ValueError("FOO")
|
||||||
|
@ -5016,6 +5016,19 @@ order (MRO) for bases """
|
||||||
with self.assertRaisesRegex(ValueError, "FOO"):
|
with self.assertRaisesRegex(ValueError, "FOO"):
|
||||||
A().foo
|
A().foo
|
||||||
|
|
||||||
|
# test case for gh-103551
|
||||||
|
class B:
|
||||||
|
@property
|
||||||
|
def __getattr__(self, name):
|
||||||
|
raise ValueError("FOO")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def foo(self):
|
||||||
|
raise NotImplementedError("BAR")
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(NotImplementedError, "BAR"):
|
||||||
|
B().foo
|
||||||
|
|
||||||
|
|
||||||
class DictProxyTests(unittest.TestCase):
|
class DictProxyTests(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Fix performance loss when accessing an object's attributes with ``__getattr__`` defined.
|
|
@ -8306,17 +8306,23 @@ _Py_slot_tp_getattr_hook(PyObject *self, PyObject *name)
|
||||||
if (getattribute == NULL ||
|
if (getattribute == NULL ||
|
||||||
(Py_IS_TYPE(getattribute, &PyWrapperDescr_Type) &&
|
(Py_IS_TYPE(getattribute, &PyWrapperDescr_Type) &&
|
||||||
((PyWrapperDescrObject *)getattribute)->d_wrapped ==
|
((PyWrapperDescrObject *)getattribute)->d_wrapped ==
|
||||||
(void *)PyObject_GenericGetAttr))
|
(void *)PyObject_GenericGetAttr)) {
|
||||||
res = PyObject_GenericGetAttr(self, name);
|
res = _PyObject_GenericGetAttrWithDict(self, name, NULL, 1);
|
||||||
else {
|
/* if res == NULL with no exception set, then it must be an
|
||||||
|
AttributeError suppressed by us. */
|
||||||
|
if (res == NULL && !PyErr_Occurred()) {
|
||||||
|
res = call_attribute(self, getattr, name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
Py_INCREF(getattribute);
|
Py_INCREF(getattribute);
|
||||||
res = call_attribute(self, getattribute, name);
|
res = call_attribute(self, getattribute, name);
|
||||||
Py_DECREF(getattribute);
|
Py_DECREF(getattribute);
|
||||||
|
if (res == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
||||||
|
PyErr_Clear();
|
||||||
|
res = call_attribute(self, getattr, name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (res == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
|
||||||
PyErr_Clear();
|
|
||||||
res = call_attribute(self, getattr, name);
|
|
||||||
}
|
|
||||||
Py_DECREF(getattr);
|
Py_DECREF(getattr);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue