Repository: numpy/numpy
File: numpy/_core/src/common/get_attr_string.h (C/C++)

Code before:
    );
}


/*
 * Lookup a special method, following the python approach of looking up
 * on the type object, rather than on the instance itself.
 *
 * Assumes that the special method is a numpy-specific one, so does not look
 * at builtin types. It does check base ndarray and numpy scalar types.
 *
 * It may make sense to just replace this with `PyObject_GetOptionalAttr`.
 */
static inline int
PyArray_LookupSpecial(
        PyObject *obj, PyObject *name_unicode, PyObject **res)
{
    PyTypeObject *tp = Py_TYPE(obj);

    /* We do not need to check for special attributes on trivial types */
    if (_is_basic_python_type(tp)) {
        *res = NULL;
        return 0;
    }

    /* We do not need to check for special attributes on array descriptor types */
    if (PyObject_TypeCheck(tp, &PyArrayDTypeMeta_Type)) {
        *res = NULL;
        return 0;
    }
    return PyObject_GetOptionalAttr((PyObject *)tp, name_unicode, res);
}


/*
 * PyArray_LookupSpecial_OnInstance:
 *
 * Implements incorrect special method lookup rules, that break the python
 * convention, and looks on the instance, not the type.
 *
 * Kept for backwards compatibility. In future, we should deprecate this.
 */
static inline int
PyArray_LookupSpecial_OnInstance(
        PyObject *obj, PyObject *name_unicode, PyObject **res)
{
    PyTypeObject *tp = Py_TYPE(obj);

    /* We do not need to check for special attributes on trivial types */
    /* Note: This check should likely be reduced on Python 3.13+ */
    if (_is_basic_python_type(tp)) {

Review comment (performance):
I don't think this is a good idea - `PyArray_LookupSpecial` is used also to look for `__array_ufunc__` and `__array_function__` and I don't think those paths should be made slower for `result_type`. 

p.s. Separately, is this actually used with `result_type`?

Code after:
}


/*
 * Lookup a special method, following the python approach of looking up
 * on the type object, rather than on the instance itself.
 *
 * Assumes that the special method is a numpy-specific one, so does not look
 * at builtin types. It does check base ndarray and numpy scalar types.
 *
 * It may make sense to just replace this with `PyObject_GetOptionalAttr`.
 */
static inline int
PyArray_LookupSpecial(
        PyObject *obj, PyObject *name_unicode, PyObject **res)
{
    PyTypeObject *tp = Py_TYPE(obj);

    /* We do not need to check for special attributes on trivial types */
    if (_is_basic_python_type(tp)) {
        *res = NULL;
        return 0;
    }

    return PyObject_GetOptionalAttr((PyObject *)tp, name_unicode, res);
}


/*
 * PyArray_LookupSpecial_OnInstance:
 *
 * Implements incorrect special method lookup rules, that break the python
 * convention, and looks on the instance, not the type.
 *
 * Kept for backwards compatibility. In future, we should deprecate this.
 */
static inline int
PyArray_LookupSpecial_OnInstance(
        PyObject *obj, PyObject *name_unicode, PyObject **res)
{
    PyTypeObject *tp = Py_TYPE(obj);

    /* We do not need to check for special attributes on trivial types */
    /* Note: This check should likely be reduced on Python 3.13+ */
    if (_is_basic_python_type(tp)) {
        *res = NULL;
        return 0;
    }

    return PyObject_GetOptionalAttr(obj, name_unicode, res);
}