summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsunmy2019 <59365878+sunmy2019@users.noreply.github.com>2023-05-01 10:10:35 (GMT)
committerGitHub <noreply@github.com>2023-05-01 10:10:35 (GMT)
commit59c27fa5cb95e2d608747a50fc675bbe2fc96beb (patch)
treee7b74de2f7e9925fbda1deb21701eed53034b102
parent487f55d5801a9ae7d79d37e259e8c377c9acd39b (diff)
downloadcpython-59c27fa5cb95e2d608747a50fc675bbe2fc96beb.zip
cpython-59c27fa5cb95e2d608747a50fc675bbe2fc96beb.tar.gz
cpython-59c27fa5cb95e2d608747a50fc675bbe2fc96beb.tar.bz2
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>
-rw-r--r--Lib/test/test_descr.py15
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2023-05-01-08-08-05.gh-issue-102213.nfH-4C.rst1
-rw-r--r--Objects/typeobject.c20
3 files changed, 28 insertions, 8 deletions
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index f17bb18..ad3eefb 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -5004,7 +5004,7 @@ order (MRO) for bases """
self.assertEqual(Parent.__subclasses__(), [])
def test_attr_raise_through_property(self):
- # add test case for gh-103272
+ # test case for gh-103272
class A:
def __getattr__(self, name):
raise ValueError("FOO")
@@ -5016,6 +5016,19 @@ order (MRO) for bases """
with self.assertRaisesRegex(ValueError, "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):
def setUp(self):
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-01-08-08-05.gh-issue-102213.nfH-4C.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-01-08-08-05.gh-issue-102213.nfH-4C.rst
new file mode 100644
index 0000000..997bef2
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-01-08-08-05.gh-issue-102213.nfH-4C.rst
@@ -0,0 +1 @@
+Fix performance loss when accessing an object's attributes with ``__getattr__`` defined.
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 38b9931..e807cc9 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -8306,17 +8306,23 @@ _Py_slot_tp_getattr_hook(PyObject *self, PyObject *name)
if (getattribute == NULL ||
(Py_IS_TYPE(getattribute, &PyWrapperDescr_Type) &&
((PyWrapperDescrObject *)getattribute)->d_wrapped ==
- (void *)PyObject_GenericGetAttr))
- res = PyObject_GenericGetAttr(self, name);
- else {
+ (void *)PyObject_GenericGetAttr)) {
+ res = _PyObject_GenericGetAttrWithDict(self, name, NULL, 1);
+ /* 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);
res = call_attribute(self, getattribute, name);
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);
return res;
}