You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
To me, _PyType_Lookup sounds like a special case -- a useful special case, but it might be good to consider in together with more variations. Off the top of my head, things that you might want to enable/disable are:
(not) looking in the instance, direct class, superclasses, metaclass
(not) invoking descriptors
(not) binding methods with Py_TPFLAGS_METHOD_DESCRIPTOR
Also: when we walk the MRO we should return the class the attribute is on (the defining class).
I guess the most important thing about this lookup is not the exact behaviour (though it's important to document that), but the fact that Python uses it to find (and cache) special methods.
Should we expose this, or _PyObject_LookupSpecial or _PyObject_LookupSpecialMethod?
Do we know how many uses those functions have, and how many of the _PyType_Lookup users resolve descriptors after the _PyType_Lookup call?
PyObject*descr=_PyType_Lookup(type, name);
if (descr!=NULL) {
descrgetfuncget=Py_TYPE(descr)->tp_descr_get;
descrsetfuncset=Py_TYPE(descr)->tp_descr_set;
if (get!=NULL&&set!=NULL) {
Py_INCREF(descr);
val=get(descr, iter->obj, (PyObject*)type);
Py_DECREF(descr);
if (val!=NULL) goto found_val;
PyErr_Clear();
}
}
pythonnet (src/runtime/Types/MetaType.cs):
publicstaticinttp_setattro(BorrowedReferencetp, BorrowedReferencename, BorrowedReferencevalue)
{
BorrowedReferencedescr=Runtime._PyType_Lookup(tp, name);
if (descr!=null)
{
BorrowedReferencedt=Runtime.PyObject_TYPE(descr);
if (dt==Runtime.PyWrapperDescriptorType||dt==Runtime.PyMethodType||typeof(ExtensionType).IsInstanceOfType(GetManagedObject(descr))
)
{
IntPtrfp=Util.ReadIntPtr(dt, TypeOffset.tp_descr_set);
if (fp!=IntPtr.Zero)
{
returnNativeCall.Int_Call_3(fp, descr, name, value);
}
Exceptions.SetError(Exceptions.AttributeError, "attribute is read-only");
return-1;
}
}
intres=Runtime.PyObject_GenericSetAttr(tp, name, value);
Runtime.PyType_Modified(tp);
returnres;
}
sentencepiece: code generated by SWIG.
#ifdefSWIGPYTHON_BUILTINSWIGRUNTIMEintSWIG_Python_NonDynamicSetAttr(PyObject*obj, PyObject*name, PyObject*value) {
...
descr=_PyType_Lookup(tp, name);
f=NULL;
if (descr!=NULL)
f=descr->ob_type->tp_descr_set;
if (!f) {
if (PyString_Check(name)) {
encoded_name=name;
SWIG_Py_INCREF(name);
} else {
encoded_name=PyUnicode_AsUTF8String(name);
if (!encoded_name)
goto done;
}
PyErr_Format(PyExc_AttributeError, "'%.100s' object has no attribute '%.200s'", tp->tp_name, PyString_AsString(encoded_nameSWIG_Py_DECREF(encoded_name);
} else {
res=f(descr, obj, value);
}
yappi:
// get name from type+namemo=_PyType_Lookup((PyTypeObject*)obj_type, name);
Py_XINCREF(mo);
...
if (mo!=NULL) {
pit->name=PyObject_Repr(mo);
Py_DECREF(mo);
returnpit;
}
The C API Working Group decided to not add int PyType_Lookup(PyTypeObject *type, PyObject *name, PyObject **attr) API: capi-workgroup/decisions#83. So I close the issue. For now, the status quo is to keep the private _PyType_Lookup() function.
Activity
pythongh-139847: Add PyType_Lookup() function
pythongh-139847: Add PyType_Lookup() function
markshannon commentedon Oct 10, 2025
This does seem to be filling a gap in the C API.
encukou commentedon Oct 10, 2025
To me,
_PyType_Lookupsounds like a special case -- a useful special case, but it might be good to consider in together with more variations. Off the top of my head, things that you might want to enable/disable are:Py_TPFLAGS_METHOD_DESCRIPTORAlso: when we walk the MRO we should return the class the attribute is on (the defining class).
encukou commentedon Oct 10, 2025
I had some notes lying around; so I collected them here: https://discuss.python.org/t/api-for-special-attribute-lookup/104288
encukou commentedon Oct 20, 2025
I guess the most important thing about this lookup is not the exact behaviour (though it's important to document that), but the fact that Python uses it to find (and cache) special methods.
Should we expose this, or
_PyObject_LookupSpecialor_PyObject_LookupSpecialMethod?Do we know how many uses those functions have, and how many of the
_PyType_Lookupusers resolve descriptors after the_PyType_Lookupcall?vstinner commentedon Dec 3, 2025
I looked at some projects to see how
_PyType_Lookup()is used.mypyc: C code emitted by mypyc:
msgspec:
pythonnet (
src/runtime/Types/MetaType.cs):sentencepiece: code generated by SWIG.
yappi:
vstinner commentedon Feb 10, 2026
The C API Working Group decided to not add
int PyType_Lookup(PyTypeObject *type, PyObject *name, PyObject **attr)API: capi-workgroup/decisions#83. So I close the issue. For now, the status quo is to keep the private_PyType_Lookup()function.