numpy: formal definition of "array_like" objects?

In numpy, the constructors of many objects accept an "array_like" as first argument. Is there a definition of a such object, either as an abstract meta class, or documentation of the methods is should contain??

It turns out almost anything is technically an array-like. "Array-like" is more of a statement of how the input will be interpreted than a restriction on what the input can be; if a parameter is documented as array-like, NumPy will try to interpret it as an array.

There is no formal definition of array-like beyond the nearly tautological one -- an array-like is any Python object that np.array can convert to an ndarray. To go beyond this, you'd need to study the source code.

    NPY_NO_EXPORT PyObject *
    PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth,
                    int max_depth, int flags, PyObject *context)
         * This is the main code to make a NumPy array from a Python
         * Object.  It is called from many different places.
        PyArrayObject *arr = NULL, *ret;
        PyArray_Descr *dtype = NULL;
        int ndim = 0;
        npy_intp dims[NPY_MAXDIMS];

        /* Get either the array or its parameters if it isn't an array */
        if (PyArray_GetArrayParamsFromObject(op, newtype,
                            0, &dtype,
                            &ndim, dims, &arr, context) < 0) {
            return NULL;

Particularly interesting is PyArray_GetArrayParamsFromObject, whose comments enumerate the types of objects np.array expects:

    PyArray_GetArrayParamsFromObject(PyObject *op,
                            PyArray_Descr *requested_dtype,
                            npy_bool writeable,
                            PyArray_Descr **out_dtype,
                            int *out_ndim, npy_intp *out_dims,
                            PyArrayObject **out_arr, PyObject *context)
        PyObject *tmp;

        /* If op is an array */

        /* If op is a NumPy scalar */

        /* If op is a Python scalar */

        /* If op supports the PEP 3118 buffer interface */

        /* If op supports the __array_struct__ or __array_interface__ interface */

         * If op supplies the __array__ function.
         * The documentation says this should produce a copy, so
         * we skip this method if writeable is true, because the intent
         * of writeable is to modify the operand.
         * XXX: If the implementation is wrong, and/or if actual
         *      usage requires this behave differently,
         *      this should be changed!

        /* Try to treat op as a list of lists */

        /* Anything can be viewed as an object, unless it needs to be writeable */


So by studying the source code we can conclude an array-like is