Skip to content

Commit 41d0922

Browse files
gh-157840: Special-case member descriptors when using hasattr (GH-157866)
1 parent de0d976 commit 41d0922

2 files changed

Lines changed: 15 additions & 0 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Speed up calls to :func:`hasattr` and three-argument :func:`getattr` for
2+
unassigned attributes in an object's :attr:`~object.__slots__` by roughly 6x.

Objects/object.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1924,6 +1924,19 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name,
19241924
if (descr != NULL) {
19251925
f = Py_TYPE(descr)->tp_descr_get;
19261926
if (f != NULL && PyDescr_IsData(descr)) {
1927+
// gh-157840: We special-case member descriptors here to avoid
1928+
// allocating an extra AttributeError
1929+
if (suppress && Py_IS_TYPE(descr, &PyMemberDescr_Type)) {
1930+
PyMemberDef *member = ((PyMemberDescrObject *)descr)->d_member;
1931+
if (member->type == Py_T_OBJECT_EX
1932+
&& !(member->flags & Py_AUDIT_READ)
1933+
&& PyObject_TypeCheck(obj, PyDescr_TYPE(descr))) {
1934+
PyObject **addr = _PyMember_GetOffset(obj, member);
1935+
if (FT_ATOMIC_LOAD_PTR(*addr) == NULL) {
1936+
goto done;
1937+
}
1938+
}
1939+
}
19271940
res = f(descr, obj, (PyObject *)Py_TYPE(obj));
19281941
if (res == NULL && suppress &&
19291942
PyErr_ExceptionMatches(PyExc_AttributeError)) {

0 commit comments

Comments
 (0)