]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-102213: Optimize the performance of `__getattr__` (GH-102248)
authorwangxiang-hz <34048878+wangxiang-hz@users.noreply.github.com>
Sat, 11 Mar 2023 11:11:37 +0000 (19:11 +0800)
committerGitHub <noreply@github.com>
Sat, 11 Mar 2023 11:11:37 +0000 (19:11 +0800)
When __getattr__ is defined, python with try to find an attribute using _PyObject_GenericGetAttrWithDict
find nothing is reasonable so we don't need an exception, it will hurt performance.

Include/internal/pycore_object.h
Misc/NEWS.d/next/Core and Builtins/2023-02-26-13-12-55.gh-issue-102213.fTH8X7.rst [new file with mode: 0644]
Objects/object.c
Objects/typeobject.c

index e15685f174ebcfe8b2eb7923c0c4919a49c2339e..318e6f3371c0c35b70167dab56206b6cc7384c5e 100644 (file)
@@ -370,6 +370,7 @@ extern void _PyObject_FreeInstanceAttributes(PyObject *obj);
 extern int _PyObject_IsInstanceDictEmpty(PyObject *);
 extern int _PyType_HasSubclasses(PyTypeObject *);
 extern PyObject* _PyType_GetSubclasses(PyTypeObject *);
+extern PyObject* _PyObject_GenericTryGetAttr(PyObject *, PyObject *);
 
 // Access macro to the members which are floating "behind" the object
 static inline PyMemberDef* _PyHeapType_GET_MEMBERS(PyHeapTypeObject *etype) {
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-26-13-12-55.gh-issue-102213.fTH8X7.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-26-13-12-55.gh-issue-102213.fTH8X7.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 38da4d497a96e72311ee46e6d95074fa12a50559..dff5e2afa16ab84c051e0e3e3a0dcb368f79e3f2 100644 (file)
@@ -1405,6 +1405,12 @@ PyObject_GenericGetAttr(PyObject *obj, PyObject *name)
     return _PyObject_GenericGetAttrWithDict(obj, name, NULL, 0);
 }
 
+PyObject *
+_PyObject_GenericTryGetAttr(PyObject *obj, PyObject *name)
+{
+    return _PyObject_GenericGetAttrWithDict(obj, name, NULL, 1);
+}
+
 int
 _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
                                  PyObject *value, PyObject *dict)
index f486b83fd69e6482ea4a26cecbd9685176d78c22..f0654c239f66358430a440d73d1bcefaf9f2cd1b 100644 (file)
@@ -8247,14 +8247,17 @@ _Py_slot_tp_getattr_hook(PyObject *self, PyObject *name)
         (Py_IS_TYPE(getattribute, &PyWrapperDescr_Type) &&
          ((PyWrapperDescrObject *)getattribute)->d_wrapped ==
          (void *)PyObject_GenericGetAttr))
-        res = PyObject_GenericGetAttr(self, name);
+        /* finding nothing is reasonable when __getattr__ is defined */
+        res = _PyObject_GenericTryGetAttr(self, name);
     else {
         Py_INCREF(getattribute);
         res = call_attribute(self, getattribute, name);
         Py_DECREF(getattribute);
     }
-    if (res == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
-        PyErr_Clear();
+    if (res == NULL) {
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_Clear();
+        }
         res = call_attribute(self, getattr, name);
     }
     Py_DECREF(getattr);