https://github.com/python/cpython/commit/41d09220bda74cda6897a4e807d7af0edaff1fd8
commit: 41d09220bda74cda6897a4e807d7af0edaff1fd8
branch: main
author: Peter Bierma <[email protected]>
committer: ZeroIntensity <[email protected]>
date: 2026-09-20T22:08:23Z
summary:

gh-157840: Special-case member descriptors when using `hasattr` (GH-157866)

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2026-09-20-12-11-01.gh-issue-157840.EAo1Kp.rst
M Objects/object.c

diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2026-09-20-12-11-01.gh-issue-157840.EAo1Kp.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-20-12-11-01.gh-issue-157840.EAo1Kp.rst
new file mode 100644
index 000000000000000..c2212267ce6fa4b
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-20-12-11-01.gh-issue-157840.EAo1Kp.rst
@@ -0,0 +1,2 @@
+Speed up calls to :func:`hasattr` and three-argument :func:`getattr` for
+unassigned attributes in an object's :attr:`~object.__slots__` by roughly 6x.
diff --git a/Objects/object.c b/Objects/object.c
index 971ac1b7a686693..c7aeba0cee22c68 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -1924,6 +1924,19 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject 
*name,
     if (descr != NULL) {
         f = Py_TYPE(descr)->tp_descr_get;
         if (f != NULL && PyDescr_IsData(descr)) {
+            // gh-157840: We special-case member descriptors here to avoid
+            // allocating an extra AttributeError
+            if (suppress && Py_IS_TYPE(descr, &PyMemberDescr_Type)) {
+                PyMemberDef *member = ((PyMemberDescrObject *)descr)->d_member;
+                if (member->type == Py_T_OBJECT_EX
+                    && !(member->flags & Py_AUDIT_READ)
+                    && PyObject_TypeCheck(obj, PyDescr_TYPE(descr))) {
+                    PyObject **addr = _PyMember_GetOffset(obj, member);
+                    if (FT_ATOMIC_LOAD_PTR(*addr) == NULL) {
+                        goto done;
+                    }
+                }
+            }
             res = f(descr, obj, (PyObject *)Py_TYPE(obj));
             if (res == NULL && suppress &&
                     PyErr_ExceptionMatches(PyExc_AttributeError)) {

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to