]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-102213: Optimize the performance of `__getattr__` (GH-103761)
authorsunmy2019 <59365878+sunmy2019@users.noreply.github.com>
Mon, 1 May 2023 10:10:35 +0000 (18:10 +0800)
committerGitHub <noreply@github.com>
Mon, 1 May 2023 10:10:35 +0000 (18:10 +0800)
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>
Lib/test/test_descr.py
Misc/NEWS.d/next/Core and Builtins/2023-05-01-08-08-05.gh-issue-102213.nfH-4C.rst [new file with mode: 0644]
Objects/typeobject.c

index f17bb1813b9d87c3847b98cf93afb39cbed8b12b..ad3eefba365856504439fce03ec03a66fe9d1bed 100644 (file)
@@ -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 (file)
index 0000000..997bef2
--- /dev/null
@@ -0,0 +1 @@
+Fix performance loss when accessing an object's attributes with ``__getattr__``  defined.
index 38b99315457a58d7900e853f69f9cde4a5c594d3..e807cc90faa16a6bcb52f6db63b9c3ba132ba020 100644 (file)
@@ -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;
 }