NumPy-源码解析-六十七-

72 阅读56分钟

NumPy 源码解析(六十七)

.\numpy\numpy\_core\src\multiarray\item_selection.h

#ifndef NUMPY_CORE_SRC_MULTIARRAY_ITEM_SELECTION_H_
#define NUMPY_CORE_SRC_MULTIARRAY_ITEM_SELECTION_H_

/*
 * Counts the number of True values in a raw boolean array. This
 * is a low-overhead function which does no heap allocations.
 *
 * Returns -1 on error.
 */
// 声明一个函数 count_boolean_trues,用于计算原始布尔数组中 True 的数量
NPY_NO_EXPORT npy_intp
count_boolean_trues(int ndim, char *data, npy_intp const *ashape, npy_intp const *astrides);

/*
 * Gets a single item from the array, based on a single multi-index
 * array of values, which must be of length PyArray_NDIM(self).
 */
// 声明一个函数 PyArray_MultiIndexGetItem,从数组中获取单个元素,基于给定的多重索引数组
NPY_NO_EXPORT PyObject *
PyArray_MultiIndexGetItem(PyArrayObject *self, const npy_intp *multi_index);

/*
 * Sets a single item in the array, based on a single multi-index
 * array of values, which must be of length PyArray_NDIM(self).
 *
 * Returns 0 on success, -1 on failure.
 */
// 声明一个函数 PyArray_MultiIndexSetItem,向数组中设置单个元素,基于给定的多重索引数组
NPY_NO_EXPORT int
PyArray_MultiIndexSetItem(PyArrayObject *self, const npy_intp *multi_index,
                                                PyObject *obj);

#endif  /* NUMPY_CORE_SRC_MULTIARRAY_ITEM_SELECTION_H_ */

.\numpy\numpy\_core\src\multiarray\iterators.c

/*
 * 定义宏,禁用过时的 NumPy API 并设置为当前版本
 */
#define NPY_NO_DEPRECATED_API NPY_API_VERSION

/*
 * 定义宏,用于 MultiArray 模块
 */
#define _MULTIARRAYMODULE

/*
 * 清除 PY_SSIZE_T_CLEAN 宏定义
 */
#define PY_SSIZE_T_CLEAN

/*
 * 包含 Python.h 头文件,这是所有 Python C API 的入口点
 */
#include <Python.h>

/*
 * 包含 structmember.h 头文件,用于定义结构体成员访问的宏
 */
#include <structmember.h>

/*
 * 包含 NumPy 的 arrayobject.h 头文件,用于 NumPy 数组对象的操作
 */
#include "numpy/arrayobject.h"

/*
 * 包含 NumPy 的 arrayscalars.h 头文件,定义数组标量对象的相关操作
 */
#include "numpy/arrayscalars.h"

/*
 * 包含 NumPy 的 npy_math.h 头文件,提供数学运算相关的宏和函数声明
 */
#include "numpy/npy_math.h"

/*
 * 包含 numpy 的配置文件 npy_config.h
 */
#include "npy_config.h"

/*
 * 包含 NumPy 的 arrayobject.h 头文件,定义数组对象的操作
 */
#include "arrayobject.h"

/*
 * 包含 iterators.h 头文件,定义了与迭代器相关的操作
 */
#include "iterators.h"

/*
 * 包含 ctors.h 头文件,用于定义构造函数和析构函数
 */
#include "ctors.h"

/*
 * 包含 common.h 头文件,提供了通用的宏和函数定义
 */
#include "common.h"

/*
 * 包含 conversion_utils.h 头文件,包含了数据类型转换的工具函数
 */
#include "conversion_utils.h"

/*
 * 包含 dtypemeta.h 头文件,用于处理数据类型元信息
 */
#include "dtypemeta.h"

/*
 * 包含 array_coercion.h 头文件,包含了数组强制转换相关的操作
 */
#include "array_coercion.h"

/*
 * 包含 item_selection.h 头文件,定义了数组元素选择的操作
 */
#include "item_selection.h"

/*
 * 包含 lowlevel_strided_loops.h 头文件,提供了低级别的分块循环操作
 */
#include "lowlevel_strided_loops.h"

/*
 * 包含 array_assign.h 头文件,定义了数组赋值的操作
 */
#include "array_assign.h"

/*
 * 定义宏 NEWAXIS_INDEX 为 -1,用于表示新轴索引
 */
#define NEWAXIS_INDEX -1

/*
 * 定义宏 ELLIPSIS_INDEX 为 -2,用于表示省略号索引
 */
#define ELLIPSIS_INDEX -2

/*
 * 定义宏 SINGLE_INDEX 为 -3,用于表示单一索引
 */
#define SINGLE_INDEX -3

/*
 * 尝试将 Python 对象 o 转换为 npy_intp 类型的索引值 v,不设置异常
 * 如果转换成功返回 1,否则返回 0
 */
static int
coerce_index(PyObject *o, npy_intp *v)
{
    *v = PyArray_PyIntAsIntp(o);

    if ((*v) == -1 && PyErr_Occurred()) {
        PyErr_Clear();
        return 0;
    }
    return 1;
}

/*
 * 将索引元组的一个元素转换为步长和步数,返回起始索引
 * 非切片操作通过 n_steps 返回 NEWAXIS_INDEX、ELLIPSIS_INDEX 或 SINGLE_INDEX
 */
NPY_NO_EXPORT npy_intp
parse_index_entry(PyObject *op, npy_intp *step_size,
                  npy_intp *n_steps, npy_intp max,
                  int axis, int check_index)
{
    npy_intp i;

    if (op == Py_None) {
        *n_steps = NEWAXIS_INDEX;
        i = 0;
    }
    else if (op == Py_Ellipsis) {
        *n_steps = ELLIPSIS_INDEX;
        i = 0;
    }
    else if (PySlice_Check(op)) {
        npy_intp stop;
        if (PySlice_GetIndicesEx(op, max, &i, &stop, step_size, n_steps) < 0) {
            goto fail;
        }
        if (*n_steps <= 0) {
            *n_steps = 0;
            *step_size = 1;
            i = 0;
        }
    }
    else if (coerce_index(op, &i)) {
        *n_steps = SINGLE_INDEX;
        *step_size = 0;
        if (check_index) {
            if (check_and_adjust_index(&i, max, axis, NULL) < 0) {
                goto fail;
            }
        }
    }
    else {
        PyErr_SetString(PyExc_IndexError,
                        "each index entry must be either a "
                        "slice, an integer, Ellipsis, or "
                        "newaxis");
        goto fail;
    }
    return i;

 fail:
    return -1;
}

/*
 * 根据迭代器和坐标获取简单迭代器的数据指针
 */
static char*
get_ptr_simple(PyArrayIterObject* iter, const npy_intp *coordinates)
{
    npy_intp i;
    char *ret;

    ret = PyArray_DATA(iter->ao);

    for(i = 0; i < PyArray_NDIM(iter->ao); ++i) {
        ret += coordinates[i] * iter->strides[i];
    }

    return ret;
}
/*
 * This is common initialization code between PyArrayIterObject and
 * PyArrayNeighborhoodIterObject
 *
 * Steals a reference to the array object which gets removed at deallocation,
 * if the iterator is allocated statically and its dealloc not called, it
 * can be thought of as borrowing the reference.
 */
NPY_NO_EXPORT void
PyArray_RawIterBaseInit(PyArrayIterObject *it, PyArrayObject *ao)
{
    int nd, i;

    nd = PyArray_NDIM(ao);  /* 获取数组对象 ao 的维度数 */
    /* The legacy iterator only supports 32 dimensions */
    assert(nd <= NPY_MAXDIMS_LEGACY_ITERS);  /* 断言:维度数不超过 NPY_MAXDIMS_LEGACY_ITERS */
    PyArray_UpdateFlags(ao, NPY_ARRAY_C_CONTIGUOUS);  /* 更新数组对象 ao 的标志位,表示其是否是 C 连续的数组 */

    if (PyArray_ISCONTIGUOUS(ao)) {
        it->contiguous = 1;  /* 如果 ao 是 C 连续的,则设置迭代器 it 的 contiguous 属性为 1 */
    }
    else {
        it->contiguous = 0;  /* 否则设置为 0 */
    }

    it->ao = ao;  /* 设置迭代器 it 的 ao 属性为输入的数组对象 ao */
    it->size = PyArray_SIZE(ao);  /* 设置迭代器 it 的 size 属性为数组 ao 的总元素数 */
    it->nd_m1 = nd - 1;  /* 设置迭代器 it 的 nd_m1 属性为数组 ao 的维度数减一 */

    if (nd != 0) {
        it->factors[nd-1] = 1;  /* 初始化迭代器 it 的 factors 数组,最后一个元素为 1 */
    }

    for (i = 0; i < nd; i++) {
        it->dims_m1[i] = PyArray_DIMS(ao)[i] - 1;  /* 设置迭代器 it 的 dims_m1 数组,存储数组 ao 每个维度的上限 */
        it->strides[i] = PyArray_STRIDES(ao)[i];  /* 设置迭代器 it 的 strides 数组,存储数组 ao 每个维度的步长 */
        it->backstrides[i] = it->strides[i] * it->dims_m1[i];  /* 计算迭代器 it 的 backstrides 数组,表示反向步长 */
        if (i > 0) {
            it->factors[nd-i-1] = it->factors[nd-i] * PyArray_DIMS(ao)[nd-i];  /* 计算迭代器 it 的 factors 数组,用于索引转换 */
        }
        it->bounds[i][0] = 0;  /* 设置迭代器 it 的 bounds 数组,表示每个维度的下限 */
        it->bounds[i][1] = PyArray_DIMS(ao)[i] - 1;  /* 设置迭代器 it 的 bounds 数组,表示每个维度的上限 */
        it->limits[i][0] = 0;  /* 设置迭代器 it 的 limits 数组,表示每个维度的限制下限 */
        it->limits[i][1] = PyArray_DIMS(ao)[i] - 1;  /* 设置迭代器 it 的 limits 数组,表示每个维度的限制上限 */
        it->limits_sizes[i] = it->limits[i][1] - it->limits[i][0] + 1;  /* 计算迭代器 it 的 limits_sizes 数组,表示限制的尺寸 */
    }

    it->translate = &get_ptr_simple;  /* 设置迭代器 it 的 translate 属性为 get_ptr_simple 函数的指针 */
    PyArray_ITER_RESET(it);  /* 调用 PyArray_ITER_RESET 函数初始化迭代器 it */

    return;
}

static void
array_iter_base_dealloc(PyArrayIterObject *it)
{
    Py_XDECREF(it->ao);  /* 释放迭代器 it 的数组对象 ao 的引用 */
}

/*NUMPY_API
 * Get Iterator.
 */
NPY_NO_EXPORT PyObject *
PyArray_IterNew(PyObject *obj)
{
    /*
     * Note that internally PyArray_RawIterBaseInit may be called directly on a
     * statically allocated PyArrayIterObject.
     */
    PyArrayIterObject *it;
    PyArrayObject *ao;

    if (!PyArray_Check(obj)) {
        PyErr_BadInternalCall();  /* 如果输入对象不是数组对象,则引发错误 */
        return NULL;
    }

    ao = (PyArrayObject *)obj;  /* 将输入对象强制转换为数组对象 ao */

    if (PyArray_NDIM(ao) > NPY_MAXDIMS_LEGACY_ITERS) {
        PyErr_Format(PyExc_RuntimeError,
                "this function only supports up to 32 dimensions but "
                "the array has %d.", PyArray_NDIM(ao));  /* 如果数组对象 ao 的维度数超过限制,引发运行时错误 */
        return NULL;
    }

    it = (PyArrayIterObject *)PyArray_malloc(sizeof(PyArrayIterObject));  /* 分配内存以存储 PyArrayIterObject 结构 */
    PyObject_Init((PyObject *)it, &PyArrayIter_Type);  /* 初始化 PyObject 结构体,设置类型为 PyArrayIter_Type */
    /* it = PyObject_New(PyArrayIterObject, &PyArrayIter_Type); */
    if (it == NULL) {
        return NULL;  /* 如果内存分配失败,则返回 NULL */
    }

    Py_INCREF(ao);  /* 增加数组对象 ao 的引用计数,因为 PyArray_RawIterBaseInit 会偷走该引用 */
    PyArray_RawIterBaseInit(it, ao);  /* 初始化迭代器 it,并传入数组对象 ao */
    return (PyObject *)it;  /* 返回初始化后的迭代器 it */
}

/*NUMPY_API
 * Get Iterator broadcast to a particular shape
 */
NPY_NO_EXPORT PyObject *
PyArray_BroadcastToShape(PyObject *obj, npy_intp *dims, int nd)
{
    PyArrayIterObject *it;
    int i, diff, j, compat, k;
    PyArrayObject *ao = (PyArrayObject *)obj;

    if (PyArray_NDIM(ao) > nd) {
        goto err;  /* 如果输入数组对象 ao 的维度数大于指定的维度数 nd,跳转到错误处理标签 */
    }

    compat = 1;  /* 兼容标志置为 1 */
    diff = j = nd - PyArray_NDIM(ao);  /* 计算输入数组对象 ao 和指定维度数 nd 的差值 */
    # 对数组对象 ao 进行迭代,检查每一个维度的大小是否兼容
    for (i = 0; i < PyArray_NDIM(ao); i++, j++) {
        # 如果数组 ao 的当前维度大小为 1,则跳过
        if (PyArray_DIMS(ao)[i] == 1) {
            continue;
        }
        # 如果数组 ao 的当前维度大小与给定的 dims 数组中的大小不匹配,则设置 compat 为 0 并跳出循环
        if (PyArray_DIMS(ao)[i] != dims[j]) {
            compat = 0;
            break;
        }
    }
    # 如果不兼容,则跳转到错误处理部分
    if (!compat) {
        goto err;
    }
    # 分配内存并初始化一个 PyArrayIterObject 迭代器对象
    it = (PyArrayIterObject *)PyArray_malloc(sizeof(PyArrayIterObject));
    if (it == NULL) {
        return NULL;
    }
    # 初始化迭代器对象,设定其类型为 PyArrayIter_Type
    PyObject_Init((PyObject *)it, &PyArrayIter_Type);

    # 更新数组 ao 的标志位,表示它是 C 连续存储的数组
    PyArray_UpdateFlags(ao, NPY_ARRAY_C_CONTIGUOUS);
    # 如果数组 ao 是 C 连续存储的,则设置迭代器对象的 contiguous 属性为 1,否则为 0
    if (PyArray_ISCONTIGUOUS(ao)) {
        it->contiguous = 1;
    }
    else {
        it->contiguous = 0;
    }
    # 增加数组 ao 的引用计数
    Py_INCREF(ao);
    # 将数组 ao 赋值给迭代器对象的 ao 属性
    it->ao = ao;
    # 计算迭代器对象的总大小
    it->size = PyArray_MultiplyList(dims, nd);
    # 设置迭代器对象的最大维度数减一
    it->nd_m1 = nd - 1;
    # 如果维度数不为 0,则初始化 factors 数组中的最后一个元素为 1
    if (nd != 0) {
        it->factors[nd-1] = 1;
    }
    # 遍历各个维度,设置相关属性
    for (i = 0; i < nd; i++) {
        # 设置 dims_m1 数组的值为 dims[i] - 1
        it->dims_m1[i] = dims[i] - 1;
        # 计算 k 值,用于检查是否为 C 连续存储的数组
        k = i - diff;
        # 如果 k 小于 0 或者数组 ao 在索引 k 处的维度大小与 dims[i] 不匹配,则设置非连续存储并将 strides[i] 设置为 0
        if ((k < 0) || PyArray_DIMS(ao)[k] != dims[i]) {
            it->contiguous = 0;
            it->strides[i] = 0;
        }
        else {
            # 否则,将 strides[i] 设置为数组 ao 在索引 k 处的步长值
            it->strides[i] = PyArray_STRIDES(ao)[k];
        }
        # 设置 backstrides[i] 为 strides[i] 乘以 dims_m1[i],用于反向遍历
        it->backstrides[i] = it->strides[i] * it->dims_m1[i];
        # 如果 i 大于 0,则计算 factors 数组中的对应元素值
        if (i > 0) {
            it->factors[nd-i-1] = it->factors[nd-i] * dims[nd-i];
        }
    }
    # 将迭代器对象重置为起始状态
    PyArray_ITER_RESET(it);
    # 返回迭代器对象的 PyObject 指针类型
    return (PyObject *)it;

 err:
    # 设置错误信息,数组无法广播到正确的形状
    PyErr_SetString(PyExc_ValueError, "array is not broadcastable to "\
                    "correct shape");
    # 返回空指针,表示错误
    return NULL;
/*NUMPY_API
 * Get Iterator that iterates over all but one axis (don't use this with
 * PyArray_ITER_GOTO1D).  The axis will be over-written if negative
 * with the axis having the smallest stride.
 */
NPY_NO_EXPORT PyObject *
PyArray_IterAllButAxis(PyObject *obj, int *inaxis)
{
    PyArrayObject *arr;
    PyArrayIterObject *it;
    int axis;

    // 检查输入参数是否为 ndarray 类型
    if (!PyArray_Check(obj)) {
        PyErr_SetString(PyExc_ValueError,
                "Numpy IterAllButAxis requires an ndarray");
        return NULL;
    }
    // 将输入参数转换为 PyArrayObject 类型
    arr = (PyArrayObject *)obj;

    // 创建一个新的迭代器对象
    it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)arr);
    if (it == NULL) {
        return NULL;
    }
    // 如果数组是零维的,直接返回迭代器对象
    if (PyArray_NDIM(arr)==0) {
        return (PyObject *)it;
    }
    // 如果输入的轴数小于 0,则选择具有最小步幅的轴
    if (*inaxis < 0) {
        int i, minaxis = 0;
        npy_intp minstride = 0;
        i = 0;
        // 找到第一个非零步幅的轴
        while (minstride == 0 && i < PyArray_NDIM(arr)) {
            minstride = PyArray_STRIDE(arr,i);
            i++;
        }
        // 遍历数组的所有轴,找到步幅最小的轴
        for (i = 1; i < PyArray_NDIM(arr); i++) {
            if (PyArray_STRIDE(arr,i) > 0 &&
                PyArray_STRIDE(arr, i) < minstride) {
                minaxis = i;
                minstride = PyArray_STRIDE(arr,i);
            }
        }
        // 更新输入的轴参数为步幅最小的轴
        *inaxis = minaxis;
    }
    // 获取当前要迭代的轴
    axis = *inaxis;
    // 设置迭代器不是连续的,以便跳过特定轴
    it->contiguous = 0;
    // 调整迭代器的大小,以便不迭代指定轴上的元素
    if (it->size != 0) {
        it->size /= PyArray_DIM(arr,axis);
    }
    it->dims_m1[axis] = 0;
    it->backstrides[axis] = 0;

    /*
     * (won't fix factors so don't use
     * PyArray_ITER_GOTO1D with this iterator)
     */
    return (PyObject *)it;
}

/*NUMPY_API
 * Adjusts previously broadcasted iterators so that the axis with
 * the smallest sum of iterator strides is not iterated over.
 * Returns dimension which is smallest in the range [0,multi->nd).
 * A -1 is returned if multi->nd == 0.
 *
 * don't use with PyArray_ITER_GOTO1D because factors are not adjusted
 */
NPY_NO_EXPORT int
PyArray_RemoveSmallest(PyArrayMultiIterObject *multi)
{
    PyArrayIterObject *it;
    int i, j;
    int axis;
    npy_intp smallest;
    npy_intp sumstrides[NPY_MAXDIMS];

    // 如果 multi->nd 等于 0,则返回 -1
    if (multi->nd == 0) {
        return -1;
    }
    // 计算每个迭代器轴上步幅的总和
    for (i = 0; i < multi->nd; i++) {
        sumstrides[i] = 0;
        for (j = 0; j < multi->numiter; j++) {
            sumstrides[i] += multi->iters[j]->strides[i];
        }
    }
    // 初始化最小步幅的轴为第一个轴
    axis = 0;
    smallest = sumstrides[0];
    // 找到步幅最小的轴
    for (i = 1; i < multi->nd; i++) {
        if (sumstrides[i] < smallest) {
            axis = i;
            smallest = sumstrides[i];
        }
    }
    // 调整每个迭代器,使其不迭代最小步幅的轴
    for(i = 0; i < multi->numiter; i++) {
        it = multi->iters[i];
        it->contiguous = 0;
        if (it->size != 0) {
            it->size /= (it->dims_m1[axis]+1);
        }
        it->dims_m1[axis] = 0;
        it->backstrides[axis] = 0;
    }
    // 更新 multi 对象的大小为第一个迭代器的大小
    multi->size = multi->iters[0]->size;
    return axis;
}
static void
arrayiter_dealloc(PyArrayIterObject *it)
{
    /*
     * 注意:可以静态分配 PyArrayIterObject,这种情况下不会调用此函数。
     */
    // 调用基类的销毁函数
    array_iter_base_dealloc(it);
    // 释放 PyArrayIterObject 对象
    PyArray_free(it);
}

static Py_ssize_t
iter_length(PyArrayIterObject *self)
{
    // 返回迭代器中的元素数量
    return self->size;
}


static PyArrayObject *
iter_subscript_Bool(PyArrayIterObject *self, PyArrayObject *ind,
                    NPY_cast_info *cast_info)
{
    npy_intp counter, strides;
    int itemsize;
    npy_intp count = 0;
    char *dptr, *optr;
    PyArrayObject *ret;

    if (PyArray_NDIM(ind) != 1) {
        // 如果布尔索引数组不是一维的,抛出 ValueError 异常
        PyErr_SetString(PyExc_ValueError,
                        "boolean index array should have 1 dimension");
        return NULL;
    }
    // 获取布尔索引数组的大小
    counter = PyArray_DIMS(ind)[0];
    if (counter > self->size) {
        // 如果布尔索引数量超过迭代器的元素数量,抛出 ValueError 异常
        PyErr_SetString(PyExc_ValueError,
                        "too many boolean indices");
        return NULL;
    }

    // 获取布尔索引数组的步长
    strides = PyArray_STRIDES(ind)[0];
    /* 获取返回数组的大小 */
    // 计算布尔真值的数量
    count = count_boolean_trues(PyArray_NDIM(ind), PyArray_DATA(ind),
                                PyArray_DIMS(ind), PyArray_STRIDES(ind));
    // 获取迭代器的元素大小
    itemsize = PyArray_ITEMSIZE(self->ao);
    // 复制迭代器的描述符
    PyArray_Descr *dtype = PyArray_DESCR(self->ao);
    Py_INCREF(dtype);
    // 从描述符创建新的数组对象
    ret = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(self->ao),
                             dtype, 1, &count,
                             NULL, NULL,
                             0, (PyObject *)self->ao);
    if (ret == NULL) {
        return NULL;
    }
    if (count > 0) {
        /* 设置循环 */
        // 设置输出指针
        optr = PyArray_DATA(ret);
        // 获取布尔索引数组的大小
        counter = PyArray_DIMS(ind)[0];
        // 获取布尔索引数组的数据指针
        dptr = PyArray_DATA(ind);
        npy_intp one = 1;
        while (counter--) {
            if (*((npy_bool *)dptr) != 0) {
                char *args[2] = {self->dataptr, optr};
                npy_intp transfer_strides[2] = {itemsize, itemsize};
                // 调用类型转换函数,转换数据并写入输出数组
                if (cast_info->func(&cast_info->context, args, &one,
                                    transfer_strides, cast_info->auxdata) < 0) {
                    return NULL;
                }
                optr += itemsize;
            }
            // 移动布尔索引数组的数据指针
            dptr += strides;
            // 移动迭代器到下一个元素
            PyArray_ITER_NEXT(self);
        }
        // 重置迭代器的位置
        PyArray_ITER_RESET(self);
    }
    return ret;
}

static PyObject *
iter_subscript_int(PyArrayIterObject *self, PyArrayObject *ind,
                   NPY_cast_info *cast_info)
{
    npy_intp num;
    PyArrayObject *ret;
    PyArrayIterObject *ind_it;
    int itemsize;
    char *optr;
    npy_intp counter;
    // 检查输入数组 `ind` 的维度是否为0
    if (PyArray_NDIM(ind) == 0) {
        // 如果是0维数组,获取其数据指针指向的整数值
        num = *((npy_intp *)PyArray_DATA(ind));
        // 检查并调整索引 `num`,确保在有效范围内
        if (check_and_adjust_index(&num, self->size, -1, NULL) < 0) {
            // 若索引无效,重置迭代器并返回 NULL
            PyArray_ITER_RESET(self);
            return NULL;
        }
        else {
            // 否则,跳转到一维索引 `num` 处
            PyObject *tmp;
            PyArray_ITER_GOTO1D(self, num);
            // 将该位置的数据转换为标量对象
            tmp = PyArray_ToScalar(self->dataptr, self->ao);
            // 重置迭代器并返回临时对象 `tmp`
            PyArray_ITER_RESET(self);
            return tmp;
        }
    }

    // 获取数组 `self->ao` 的数据类型描述符并增加其引用计数
    PyArray_Descr *dtype = PyArray_DESCR(self->ao);
    Py_INCREF(dtype);
    // 从描述符创建一个新的数组对象 `ret`
    ret = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(self->ao),
                             dtype,
                             PyArray_NDIM(ind),
                             PyArray_DIMS(ind),
                             NULL, NULL,
                             0, (PyObject *)self->ao);
    // 若创建失败,返回 NULL
    if (ret == NULL) {
        return NULL;
    }

    // 获取 `ret` 的数据指针
    optr = PyArray_DATA(ret);
    // 创建 `ind` 的迭代器 `ind_it`
    ind_it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)ind);
    // 若迭代器创建失败,释放 `ret` 并返回 NULL
    if (ind_it == NULL) {
        Py_DECREF(ret);
        return NULL;
    }

    // 初始化变量
    npy_intp one = 1;
    itemsize = dtype->elsize;
    counter = ind_it->size;
    // 遍历迭代器中的每个元素
    while (counter--) {
        // 获取当前索引值 `num`
        num = *((npy_intp *)(ind_it->dataptr));
        // 检查并调整索引 `num`,确保在有效范围内
        if (check_and_adjust_index(&num, self->size, -1, NULL) < 0) {
            // 如果索引无效,清除 `ret` 并跳转到 `finish` 标签
            Py_CLEAR(ret);
            goto finish;
        }
        // 跳转到 `self` 的一维索引 `num` 处
        PyArray_ITER_GOTO1D(self, num);
        // 构建参数数组和传输步长数组,并调用 `cast_info` 中的函数进行数据类型转换
        char *args[2] = {self->dataptr, optr};
        npy_intp transfer_strides[2] = {itemsize, itemsize};
        if (cast_info->func(&cast_info->context, args, &one,
                            transfer_strides, cast_info->auxdata) < 0) {
            // 若转换失败,清除 `ret` 并跳转到 `finish` 标签
            Py_CLEAR(ret);
            goto finish;
        }
        // 更新 `optr` 指向下一个数据位置
        optr += itemsize;
        // 移动 `ind_it` 到下一个元素
        PyArray_ITER_NEXT(ind_it);
    }

 finish:
    // 释放 `ind_it` 迭代器
    Py_DECREF(ind_it);
    // 重置 `self` 迭代器
    PyArray_ITER_RESET(self);
    // 返回 `ret` 对象转换为 PyObject 类型
    return (PyObject *)ret;
}

/* Always returns arrays */
NPY_NO_EXPORT PyObject *
iter_subscript(PyArrayIterObject *self, PyObject *ind)
{
    PyArray_Descr *indtype = NULL;  // 声明一个指向数组描述符的指针变量,初始为NULL
    PyArray_Descr *dtype;  // 声明一个指向数组描述符的指针变量
    npy_intp start, step_size;  // 声明用于存储整数索引起始位置和步长的变量
    npy_intp n_steps;  // 声明用于存储步数的变量
    PyArrayObject *ret;  // 声明一个指向数组对象的指针变量,用于存储返回结果
    char *dptr;  // 声明一个指向字符的指针变量
    int size;  // 声明一个整型变量,用于存储元素大小
    PyObject *obj = NULL;  // 声明一个Python对象指针变量,初始为NULL
    PyObject *new;  // 声明一个Python对象指针变量
    NPY_cast_info cast_info = {.func = NULL};  // 声明一个结构体变量,用于存储转换函数信息,初始值为NULL

    if (ind == Py_Ellipsis) {
        ind = PySlice_New(NULL, NULL, NULL);  // 创建一个新的切片对象,用于索引操作
        obj = iter_subscript(self, ind);  // 递归调用当前函数,处理切片对象作为索引
        Py_DECREF(ind);  // 减少切片对象的引用计数
        return obj;  // 返回处理结果
    }
    if (PyTuple_Check(ind)) {
        int len;  // 声明一个整型变量,用于存储元组长度
        len = PyTuple_GET_SIZE(ind);  // 获取元组的长度
        if (len > 1) {
            goto fail;  // 如果元组长度大于1,则跳转到错误处理标签
        }
        if (len == 0) {
            Py_INCREF(self->ao);  // 增加数组对象的引用计数
            return (PyObject *)self->ao;  // 返回数组对象的Python对象指针
        }
        ind = PyTuple_GET_ITEM(ind, 0);  // 获取元组中的第一个元素作为新的索引对象
    }

    /*
     * Tuples >1d not accepted --- i.e. no newaxis
     * Could implement this with adjusted strides and dimensions in iterator
     * Check for Boolean -- this is first because Bool is a subclass of Int
     */
    PyArray_ITER_RESET(self);  // 重置数组迭代器的状态

    if (PyBool_Check(ind)) {
        int istrue = PyObject_IsTrue(ind);  // 检查布尔值是否为True
        if (istrue == -1) {
            goto fail;  // 如果检查失败,则跳转到错误处理标签
        }
        if (istrue) {
            return PyArray_ToScalar(self->dataptr, self->ao);  // 将数组中的数据转换为标量并返回
        }
        else { /* empty array */
            npy_intp ii = 0;  // 声明一个整型变量,表示空数组的长度
            dtype = PyArray_DESCR(self->ao);  // 获取数组对象的描述符
            Py_INCREF(dtype);  // 增加描述符的引用计数
            ret = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(self->ao),
                                     dtype,
                                     1, &ii,
                                     NULL, NULL, 0,
                                     (PyObject *)self->ao);  // 创建一个新的数组对象
            return (PyObject *)ret;  // 返回新创建的数组对象的Python对象指针
        }
    }

    dtype = PyArray_DESCR(self->ao);  // 获取数组对象的描述符
    size = dtype->elsize;  // 获取数组元素的大小

    /* set up a cast to handle item copying */

    NPY_ARRAYMETHOD_FLAGS transfer_flags = 0;  // 声明一个标志位变量,用于存储数组操作的标志
    npy_intp one = 1;  // 声明一个整型变量,表示步长为1
    /* We can assume the newly allocated output array is aligned */
    int is_aligned = IsUintAligned(self->ao);  // 检查数组是否按照整数对齐
    if (PyArray_GetDTypeTransferFunction(
                is_aligned, size, size, dtype, dtype, 0, &cast_info,
                &transfer_flags) < 0) {
        goto fail;  // 如果获取数据类型转换函数失败,则跳转到错误处理标签
    }

    /* Check for Integer or Slice */
    # 检查索引是否为 PyLong 或 PySlice 对象
    if (PyLong_Check(ind) || PySlice_Check(ind)) {
        # 解析索引,获取起始位置、步长和步数
        start = parse_index_entry(ind, &step_size, &n_steps,
                                  self->size, 0, 1);
        # 解析失败,跳转到错误处理
        if (start == -1) {
            goto fail;
        }
        # 若步数为省略号索引或新轴索引,抛出索引错误并跳转到错误处理
        if (n_steps == ELLIPSIS_INDEX || n_steps == NEWAXIS_INDEX) {
            PyErr_SetString(PyExc_IndexError,
                            "cannot use Ellipsis or newaxes here");
            goto fail;
        }
        # 将迭代器移动到一维数组的起始位置
        PyArray_ITER_GOTO1D(self, start);
        # 若步数为单一索引(整数)
        if (n_steps == SINGLE_INDEX) { /* Integer */
            PyObject *tmp;
            # 将当前位置的数据转换为标量对象
            tmp = PyArray_ToScalar(self->dataptr, self->ao);
            # 重置迭代器到初始状态
            PyArray_ITER_RESET(self);
            # 释放类型转换信息并返回临时对象
            NPY_cast_info_xfree(&cast_info);
            return tmp;
        }
        # 增加引用计数以防止类型被释放
        Py_INCREF(dtype);
        # 根据指定的类型和步数创建新的数组对象
        ret = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(self->ao),
                                 dtype,
                                 1, &n_steps,
                                 NULL, NULL,
                                 0, (PyObject *)self->ao);
        # 创建失败,跳转到错误处理
        if (ret == NULL) {
            goto fail;
        }
        # 获取新数组对象的数据指针
        dptr = PyArray_DATA(ret);
        # 循环处理每一个步数
        while (n_steps--) {
            char *args[2] = {self->dataptr, dptr};
            npy_intp transfer_strides[2] = {size, size};
            # 如果类型转换函数执行失败,跳转到错误处理
            if (cast_info.func(&cast_info.context, args, &one,
                               transfer_strides, cast_info.auxdata) < 0) {
                goto fail;
            }
            # 更新起始位置
            start += step_size;
            # 将迭代器移动到新的一维位置
            PyArray_ITER_GOTO1D(self, start);
            # 更新数据指针位置
            dptr += size;
        }
        # 重置迭代器到初始状态
        PyArray_ITER_RESET(self);
        # 释放类型转换信息
        NPY_cast_info_xfree(&cast_info);
        # 返回新数组对象
        return (PyObject *)ret;
    }

    /* convert to INTP array if Integer array scalar or List */
    # 获取整数类型描述符
    indtype = PyArray_DescrFromType(NPY_INTP);
    # 如果索引是整数数组标量或列表
    if (PyArray_IsScalar(ind, Integer) || PyList_Check(ind)) {
        # 增加类型描述符的引用计数
        Py_INCREF(indtype);
        # 将输入对象转换为任意类型数组
        obj = PyArray_FromAny(ind, indtype, 0, 0, NPY_ARRAY_FORCECAST, NULL);
        # 转换失败,跳转到错误处理
        if (obj == NULL) {
            goto fail;
        }
    }
    else {
        # 增加索引对象的引用计数
        Py_INCREF(ind);
        # 直接使用索引对象
        obj = ind;
    }

    /* Any remaining valid input is an array or has been turned into one */
    # 如果对象不是数组,跳转到错误处理
    if (!PyArray_Check(obj)) {
        goto fail;
    }

    /* Check for Boolean array */
    # 检查是否为布尔数组
    if (PyArray_TYPE((PyArrayObject *)obj) == NPY_BOOL) {
        # 使用布尔数组进行迭代下标操作
        ret = iter_subscript_Bool(self, (PyArrayObject *)obj, &cast_info);
        # 跳转到结束处理
        goto finish;
    }

    /* Only integer arrays left */
    # 只剩下整数数组
    if (!PyArray_ISINTEGER((PyArrayObject *)obj)) {
        # 跳转到错误处理
        goto fail;
    }

    # 增加整数类型描述符的引用计数
    Py_INCREF(indtype);
    # 将对象转换为整数类型数组
    new = PyArray_FromAny(obj, indtype, 0, 0,
                      NPY_ARRAY_FORCECAST | NPY_ARRAY_ALIGNED, NULL);
    # 转换失败,跳转到错误处理
    if (new == NULL) {
        goto fail;
    }
    # 使用整数类型数组进行迭代下标操作
    ret = (PyArrayObject *)iter_subscript_int(self, (PyArrayObject *)new,
                                              &cast_info);
    # 释放临时数组对象
    Py_DECREF(new);

 finish:
    # 释放整数类型描述符的引用
    Py_DECREF(indtype);
    # 释放输入对象的引用
    Py_DECREF(obj);
    # 释放类型转换信息
    NPY_cast_info_xfree(&cast_info);
    # 返回操作结果对象
    return (PyObject *)ret;

 fail:
    # 错误处理标签,用于跳转到错误处理部分
    // 检查是否存在 Python 异常状态
    if (!PyErr_Occurred()) {
        // 如果没有异常,设置一个索引错误异常并设定错误消息
        PyErr_SetString(PyExc_IndexError, "unsupported iterator index");
    }
    // 释放 Python 对象引用,避免内存泄漏
    Py_XDECREF(indtype);
    Py_XDECREF(obj);
    // 释放 NumPy 的类型转换信息资源,包括内存空间的释放
    NPY_cast_info_xfree(&cast_info);

    // 返回 NULL 表示函数执行失败
    return NULL;
static`
# 定义一个静态函数,用于处理布尔索引的赋值操作,将给定的值赋给迭代器指向的位置
static int
iter_ass_sub_Bool(PyArrayIterObject *self, PyArrayObject *ind,
                  PyArrayIterObject *val, NPY_cast_info *cast_info)
{
    npy_intp counter, strides;  // 定义计数器和步长变量
    char *dptr;  // 定义指向布尔索引数组数据的指针

    if (PyArray_NDIM(ind) != 1) {  // 检查布尔索引数组的维度是否为1
        PyErr_SetString(PyExc_ValueError,
                        "boolean index array should have 1 dimension");  // 抛出错误信息
        return -1;  // 返回-1,表示出错
    }

    counter = PyArray_DIMS(ind)[0];  // 获取布尔索引数组的长度
    if (counter > self->size) {  // 检查布尔索引数组长度是否超过迭代器的大小
        PyErr_SetString(PyExc_ValueError,
                        "boolean index array has too many values");  // 抛出错误信息
        return -1;  // 返回-1,表示出错
    }

    strides = PyArray_STRIDES(ind)[0];  // 获取布尔索引数组的步长
    dptr = PyArray_DATA(ind);  // 获取布尔索引数组的数据指针
    PyArray_ITER_RESET(self);  // 重置迭代器的状态
    /* Loop over Boolean array */  // 循环遍历布尔数组
    npy_intp one = 1;  // 定义一个大小为1的整数
    PyArray_Descr *dtype = PyArray_DESCR(self->ao);  // 获取迭代器所操作数组的数据类型描述符
    int itemsize = dtype->elsize;  // 获取数组元素的大小
    npy_intp transfer_strides[2] = {itemsize, itemsize};  // 定义数据传输的步长数组
    while (counter--) {  // 循环,直到计数器减为0
        if (*((npy_bool *)dptr) != 0) {  // 如果布尔数组当前位置的值不为0
            char *args[2] = {val->dataptr, self->dataptr};  // 创建一个参数数组,包含值迭代器和目标迭代器的数据指针
            if (cast_info->func(&cast_info->context, args, &one,
                                transfer_strides, cast_info->auxdata) < 0) {
                return -1;  // 如果类型转换函数返回小于0的值,表示出错,返回-1
            }
            PyArray_ITER_NEXT(val);  // 移动值迭代器到下一个位置
            if (val->index == val->size) {  // 如果值迭代器的索引等于其大小
                PyArray_ITER_RESET(val);  // 重置值迭代器的状态
            }
        }
        dptr += strides;  // 移动布尔索引数组数据指针到下一个位置
        PyArray_ITER_NEXT(self);  // 移动迭代器到下一个位置
    }
    PyArray_ITER_RESET(self);  // 最后重置迭代器的状态
    return 0;  // 返回0,表示操作成功完成
}
    # 循环直到 counter 变为 0
    while (counter--) {
        # 从指针中获取整数值,作为索引 num
        num = *((npy_intp *)(ind_it->dataptr));
        # 检查并调整索引 num,确保在有效范围内,如果不合法则返回 -1
        if (check_and_adjust_index(&num, self->size, -1, NULL) < 0) {
            # 释放索引迭代器对象并返回 -1
            Py_DECREF(ind_it);
            return -1;
        }
        # 将迭代器移动到一维数组中的 num 位置
        PyArray_ITER_GOTO1D(self, num);
        # 准备参数数组,用于类型转换函数调用
        char *args[2] = {val->dataptr, self->dataptr};
        # 调用类型转换函数,将 self 的数据转换为 val 的数据类型
        if (cast_info->func(&cast_info->context, args, &one,
                            transfer_strides, cast_info->auxdata) < 0) {
            # 如果类型转换函数调用失败,释放索引迭代器对象并返回 -1
            Py_DECREF(ind_it);
            return -1;
        }
        # 移动索引迭代器到下一个位置
        PyArray_ITER_NEXT(ind_it);
        # 移动 val 迭代器到下一个位置
        PyArray_ITER_NEXT(val);
        # 如果 val 迭代器的当前索引达到其大小,则重置为起始位置
        if (val->index == val->size) {
            PyArray_ITER_RESET(val);
        }
    }
    # 释放索引迭代器对象
    Py_DECREF(ind_it);
    # 循环执行完毕,返回 0 表示成功
    return 0;
    /*
     * 以下是iter_ass_subscript函数的具体实现,用于处理NumPy数组迭代器的元素赋值操作。
     * 根据ind参数类型的不同,实现不同的赋值逻辑。
     */

    NPY_NO_EXPORT int
    iter_ass_subscript(PyArrayIterObject *self, PyObject *ind, PyObject *val)
    {
        PyArrayObject *arrval = NULL;
        PyArrayIterObject *val_it = NULL;
        PyArray_Descr *type;
        PyArray_Descr *indtype = NULL;
        int retval = -1;
        npy_intp start, step_size;
        npy_intp n_steps;
        PyObject *obj = NULL;
        NPY_cast_info cast_info = {.func = NULL};

        // 如果val为NULL,无法删除迭代器元素,抛出TypeError异常
        if (val == NULL) {
            PyErr_SetString(PyExc_TypeError,
                            "Cannot delete iterator elements");
            return -1;
        }

        // 确保底层数组可写
        if (PyArray_FailUnlessWriteable(self->ao, "underlying array") < 0)
            return -1;

        // 处理ind为省略号(Ellipsis)的情况,递归调用自身处理
        if (ind == Py_Ellipsis) {
            ind = PySlice_New(NULL, NULL, NULL);
            retval = iter_ass_subscript(self, ind, val);
            Py_DECREF(ind);
            return retval;
        }

        // 处理ind为元组的情况,只取第一个元素处理
        if (PyTuple_Check(ind)) {
            int len;
            len = PyTuple_GET_SIZE(ind);
            if (len > 1) {
                goto finish;
            }
            ind = PyTuple_GET_ITEM(ind, 0);
        }

        // 获取底层数组的描述符
        type = PyArray_DESCR(self->ao);

        /*
         * 检查是否为布尔类型 -- 这是因为
         * 布尔类型是整数类型的子类
         */
        if (PyBool_Check(ind)) {
            retval = 0;
            int istrue = PyObject_IsTrue(ind);
            if (istrue == -1) {
                return -1;
            }
            // 如果布尔值为真,则将val打包到数组中
            if (istrue) {
                retval = PyArray_Pack(
                        PyArray_DESCR(self->ao), self->dataptr, val);
            }
            goto finish;
        }

        // 如果ind为序列或切片对象,则跳过后续处理
        if (PySequence_Check(ind) || PySlice_Check(ind)) {
            goto skip;
        }

        // 尝试将ind转换为npy_intp类型作为起始索引
        start = PyArray_PyIntAsIntp(ind);
        if (error_converting(start)) {
            PyErr_Clear();
        }
        else {
            // 检查并调整索引,然后定位到一维位置
            if (check_and_adjust_index(&start, self->size, -1, NULL) < 0) {
                goto finish;
            }
            PyArray_ITER_GOTO1D(self, start);
            // 将val打包到数组的当前位置
            retval = PyArray_Pack(PyArray_DESCR(self->ao), self->dataptr, val);
            PyArray_ITER_RESET(self);
            if (retval < 0) {
                PyErr_SetString(PyExc_ValueError,
                                "Error setting single item of array.");
            }
            goto finish;
        }

    skip:
        // 增加对类型的引用计数,并尝试从val创建一个PyArrayObject对象
        Py_INCREF(type);
        arrval = (PyArrayObject *)PyArray_FromAny(val, type, 0, 0,
                                                  NPY_ARRAY_FORCECAST, NULL);
        if (arrval == NULL) {
            return -1;
        }
        // 创建val的迭代器对象
        val_it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)arrval);
        if (val_it == NULL) {
            goto finish;
        }
        // 如果val_it的大小为0,则直接返回0
        if (val_it->size == 0) {
            retval = 0;
            goto finish;
        }

        /* 设置转换以处理将单个元素复制到arrval中 */
        NPY_ARRAYMETHOD_FLAGS transfer_flags = 0;
        npy_intp one = 1;
        int itemsize = type->elsize;
        /* 我们可以假设新分配的数组是对齐的 */
        int is_aligned = IsUintAligned(self->ao);
        // 获取数据类型转换函数
        if (PyArray_GetDTypeTransferFunction(
                    is_aligned, itemsize, itemsize, type, type, 0,
                    &cast_info, &transfer_flags) < 0) {
            goto finish;
        }

        /* 检查切片 */
    # 检查是否为切片对象
    if (PySlice_Check(ind)) {
        # 解析切片对象,获取起始位置、步长和步数
        start = parse_index_entry(ind, &step_size, &n_steps, self->size, 0, 0);
        # 如果解析失败,跳转至结束标签
        if (start == -1) {
            goto finish;
        }
        # 如果步数为省略号或新轴索引,抛出索引错误并跳转至结束标签
        if (n_steps == ELLIPSIS_INDEX || n_steps == NEWAXIS_INDEX) {
            PyErr_SetString(PyExc_IndexError,
                            "cannot use Ellipsis or newaxes here");
            goto finish;
        }
        # 将迭代器移到一维数组的指定位置
        PyArray_ITER_GOTO1D(self, start);
        # 设置数据传输步长
        npy_intp transfer_strides[2] = {itemsize, itemsize};
        # 如果步数为单一索引
        if (n_steps == SINGLE_INDEX) {
            # 设置参数数组,并进行类型转换和数据传输
            char *args[2] = {PyArray_DATA(arrval), self->dataptr};
            if (cast_info.func(&cast_info.context, args, &one,
                               transfer_strides, cast_info.auxdata) < 0) {
                goto finish;
            }
            # 重置迭代器状态
            PyArray_ITER_RESET(self);
            # 返回成功标志
            retval = 0;
            # 跳转至结束标签
            goto finish;
        }
        # 多步索引时循环处理
        while (n_steps--) {
            # 设置参数数组,并进行类型转换和数据传输
            char *args[2] = {val_it->dataptr, self->dataptr};
            if (cast_info.func(&cast_info.context, args, &one,
                               transfer_strides, cast_info.auxdata) < 0) {
                goto finish;
            }
            # 更新起始位置
            start += step_size;
            # 将迭代器移到更新后的位置
            PyArray_ITER_GOTO1D(self, start);
            # 移动值迭代器到下一个位置
            PyArray_ITER_NEXT(val_it);
            # 如果值迭代器超出范围,重置它
            if (val_it->index == val_it->size) {
                PyArray_ITER_RESET(val_it);
            }
        }
        # 重置主迭代器状态
        PyArray_ITER_RESET(self);
        # 返回成功标志
        retval = 0;
        # 跳转至结束标签
        goto finish;
    }

    /* 将对象转换为 INTP 数组,如果是整数数组标量或列表 */
    indtype = PyArray_DescrFromType(NPY_INTP);
    if (PyList_Check(ind)) {
        # 增加引用计数,将对象转换为数组
        Py_INCREF(indtype);
        obj = PyArray_FromAny(ind, indtype, 0, 0, NPY_ARRAY_FORCECAST, NULL);
    }
    else {
        # 增加引用计数
        Py_INCREF(ind);
        obj = ind;
    }

    # 检查对象是否为数组
    if (obj != NULL && PyArray_Check(obj)) {
        /* 检查是否为布尔数组 */
        if (PyArray_TYPE((PyArrayObject *)obj)==NPY_BOOL) {
            # 如果是布尔数组,执行布尔索引赋值操作
            if (iter_ass_sub_Bool(self, (PyArrayObject *)obj,
                                  val_it, &cast_info) < 0) {
                goto finish;
            }
            # 设置返回成功标志
            retval=0;
        }
        /* 检查是否为整数数组 */
        else if (PyArray_ISINTEGER((PyArrayObject *)obj)) {
            # 增加引用计数,将对象转换为整数数组
            PyObject *new;
            Py_INCREF(indtype);
            new = PyArray_CheckFromAny(obj, indtype, 0, 0,
                           NPY_ARRAY_FORCECAST | NPY_ARRAY_BEHAVED_NS, NULL);
            # 减少原对象的引用计数
            Py_DECREF(obj);
            obj = new;
            # 如果转换失败,跳转至结束标签
            if (new == NULL) {
                goto finish;
            }
            # 如果是整数数组,执行整数索引赋值操作
            if (iter_ass_sub_int(self, (PyArrayObject *)obj,
                                 val_it, &cast_info) < 0) {
                goto finish;
            }
            # 设置返回成功标志
            retval = 0;
        }
    }

 finish:
    # 如果没有发生异常且返回值小于0,设置索引错误异常
    if (!PyErr_Occurred() && retval < 0) {
        PyErr_SetString(PyExc_IndexError, "unsupported iterator index");
    }
    # 释放对象类型描述符的引用
    Py_XDECREF(indtype);
    # 释放对象的引用
    Py_XDECREF(obj);
    # 释放值迭代器的引用
    Py_XDECREF(val_it);
    # 释放数组值的引用
    Py_XDECREF(arrval);
    # 调用函数 NPY_cast_info_xfree,释放 cast_info 指向的内存
    NPY_cast_info_xfree(&cast_info);
    # 返回函数的结果值给调用者
    return retval;
}

static PyMappingMethods iter_as_mapping = {
    (lenfunc)iter_length,                   /* mp_length */
    (binaryfunc)iter_subscript,             /* mp_subscript */
    (objobjargproc)iter_ass_subscript,      /* mp_ass_subscript */
};

/* Two options:
 *  1) underlying array is contiguous
 *     -- return 1-d wrapper around it
 *  2) underlying array is not contiguous
 *     -- make new 1-d contiguous array with updateifcopy flag set
 *        to copy back to the old array
 *
 *  If underlying array is readonly, then we make the output array readonly
 *     and updateifcopy does not apply.
 *
 *  Changed 2017-07-21, 1.14.0.
 *
 *  In order to start the process of removing UPDATEIFCOPY, see gh-7054, the
 *  behavior is changed to always return an non-writeable copy when the base
 *  array is non-contiguous. Doing that will hopefully smoke out those few
 *  folks who assign to the result with the expectation that the base array
 *  will be changed. At a later date non-contiguous arrays will always return
 *  writeable copies.
 *
 *  Note that the type and argument expected for the __array__ method is
 *  ignored.
 */
static PyArrayObject *
iter_array(PyArrayIterObject *it, PyObject *NPY_UNUSED(args), PyObject *NPY_UNUSED(kwds))
{
    PyArrayObject *ret;
    npy_intp size;

    size = PyArray_SIZE(it->ao);  // 获取数组对象 `it` 的大小

    Py_INCREF(PyArray_DESCR(it->ao));  // 增加数组描述符的引用计数

    if (PyArray_ISCONTIGUOUS(it->ao)) {
        // 如果数组是连续的,则创建一个基于原数组的一维包装器
        ret = (PyArrayObject *)PyArray_NewFromDescrAndBase(
                &PyArray_Type, PyArray_DESCR(it->ao),
                1, &size, NULL, PyArray_DATA(it->ao),
                PyArray_FLAGS(it->ao), (PyObject *)it->ao, (PyObject *)it->ao);
        if (ret == NULL) {
            return NULL;
        }
    }
    else {
        // 如果数组不是连续的,则创建一个新的一维连续数组,并设置 updateifcopy 标志
        ret = (PyArrayObject *)PyArray_NewFromDescr(
                &PyArray_Type, PyArray_DESCR(it->ao), 1, &size,
                NULL, NULL, 0, (PyObject *)it->ao);
        if (ret == NULL) {
            return NULL;
        }
        if (PyArray_CopyAnyInto(ret, it->ao) < 0) {
            Py_DECREF(ret);
            return NULL;
        }
        // 清除可写标志,使得输出数组为只读状态
        PyArray_CLEARFLAGS(ret, NPY_ARRAY_WRITEABLE);
    }
    return ret;  // 返回创建的数组对象
}

static PyObject *
iter_copy(PyArrayIterObject *it, PyObject *args)
{
    if (!PyArg_ParseTuple(args, "")) {
        return NULL;
    }
    // 返回数组的扁平化视图
    return PyArray_Flatten(it->ao, 0);
}

static PyMethodDef iter_methods[] = {
    /* to get array */
    {"__array__",
        (PyCFunction)iter_array,           // 对应的 C 函数为 iter_array
        METH_VARARGS | METH_KEYWORDS, NULL},  // 方法接受位置参数和关键字参数

    {"copy",
        (PyCFunction)iter_copy,            // 对应的 C 函数为 iter_copy
        METH_VARARGS, NULL},                // 方法接受位置参数

    {NULL, NULL, 0, NULL}           /* sentinel */
};

static PyObject *
iter_richcompare(PyArrayIterObject *self, PyObject *other, int cmp_op)
{
    PyArrayObject *new;
    PyObject *ret;

    new = (PyArrayObject *)iter_array(self, NULL, NULL);  // 获取数组的新视图
    if (new == NULL) {
        return NULL;
    }

    // 使用数组的比较方法进行比较
    ret = array_richcompare(new, other, cmp_op);

    // 解析写回复制标志
    PyArray_ResolveWritebackIfCopy(new);

    Py_DECREF(new);  // 减少数组视图的引用计数

    // 返回比较的结果
    return ret;
}
    return ret;
/** END of Array Iterator **/

// 设置迭代器成员变量的定义
static PyMemberDef iter_members[] = {
    // base 成员,对象类型,偏移量,只读,无特殊处理函数
    {"base",
        T_OBJECT,
        offsetof(PyArrayIterObject, ao),
        READONLY, NULL},
    // 数组结束标志
    {NULL, 0, 0, 0, NULL},
};

// 定义获取迭代器索引的函数
static PyObject *
iter_index_get(PyArrayIterObject *self, void *NPY_UNUSED(ignored))
{
    // 返回迭代器当前的索引值
    return PyArray_PyIntFromIntp(self->index);
}

// 定义获取迭代器坐标的函数
static PyObject *
iter_coords_get(PyArrayIterObject *self, void *NPY_UNUSED(ignored))
{
    int nd;
    nd = PyArray_NDIM(self->ao);
    // 如果数组是连续存储的
    if (self->contiguous) {
        /*
         * 坐标不被跟踪 ---
         * 需要根据索引生成
         */
        npy_intp val;
        int i;
        val = self->index;
        for (i = 0; i < nd; i++) {
            // 如果因子不为零,计算坐标
            if (self->factors[i] != 0) {
                self->coordinates[i] = val / self->factors[i];
                val = val % self->factors[i];
            } else {
                self->coordinates[i] = 0;
            }
        }
    }
    // 返回坐标的整数元组对象
    return PyArray_IntTupleFromIntp(nd, self->coordinates);
}

// 定义获取器的获取和设置函数
static PyGetSetDef iter_getsets[] = {
    // 获取索引的属性
    {"index",
        (getter)iter_index_get,
        NULL, NULL, NULL},
    // 获取坐标的属性
    {"coords",
        (getter)iter_coords_get,
        NULL, NULL, NULL},
    // 结束标志
    {NULL, NULL, NULL, NULL, NULL},
};

// 定义数组迭代器类型对象
NPY_NO_EXPORT PyTypeObject PyArrayIter_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    // 对象类型名
    .tp_name = "numpy.flatiter",
    // 基本大小
    .tp_basicsize = sizeof(PyArrayIterObject),
    // 析构函数
    .tp_dealloc = (destructor)arrayiter_dealloc,
    // 映射接口
    .tp_as_mapping = &iter_as_mapping,
    // 标志
    .tp_flags = Py_TPFLAGS_DEFAULT,
    // 富比较函数
    .tp_richcompare = (richcmpfunc)iter_richcompare,
    // 迭代下一个函数
    .tp_iternext = (iternextfunc)arrayiter_next,
    // 方法
    .tp_methods = iter_methods,
    // 成员变量
    .tp_members = iter_members,
    // 获取器
    .tp_getset = iter_getsets,
};

// 调整索引对象迭代器的维度和步长
/*NUMPY_API*/
NPY_NO_EXPORT int
PyArray_Broadcast(PyArrayMultiIterObject *mit)
{
    int i, nd, k, j;
    int src_iter = -1;  /* Initializing avoids a compiler warning. */
    npy_intp tmp;
    PyArrayIterObject *it;

    // 发现广播的维度数量
    /* 遍历所有迭代器,确定迭代器中最大的维度数 */
    for (i = 0, nd = 0; i < mit->numiter; i++) {
        nd = PyArray_MAX(nd, PyArray_NDIM(mit->iters[i]->ao));
    }
    mit->nd = nd;

    /* 在每个维度中发现广播形状 */
    for (i = 0; i < nd; i++) {
        mit->dimensions[i] = 1;
        for (j = 0; j < mit->numiter; j++) {
            it = mit->iters[j];
            /* 如果数组的维度小于最大维度nd,就在其前面添加1 */
            k = i + PyArray_NDIM(it->ao) - nd;
            if (k >= 0) {
                tmp = PyArray_DIMS(it->ao)[k];
                if (tmp == 1) {
                    continue;
                }
                /* 如果mit->dimensions[i]为1,将其设置为tmp */
                if (mit->dimensions[i] == 1) {
                    mit->dimensions[i] = tmp;
                    src_iter = j;
                }
                /* 如果mit->dimensions[i]不等于tmp,则设置形状不匹配的异常 */
                else if (mit->dimensions[i] != tmp) {
                    set_shape_mismatch_exception(mit, src_iter, j);
                    return -1;
                }
            }
        }
    }

    /*
     * 重设每个迭代器对象的迭代器维度和步长 -- 使用值为0的步长进行广播
     * 需要检查溢出
     */
    tmp = PyArray_OverflowMultiplyList(mit->dimensions, mit->nd);
    if (tmp < 0) {
        PyErr_SetString(PyExc_ValueError,
                        "broadcast dimensions too large.");
        return -1;
    }
    mit->size = tmp;
    for (i = 0; i < mit->numiter; i++) {
        it = mit->iters[i];
        it->nd_m1 = mit->nd - 1;
        it->size = tmp;
        nd = PyArray_NDIM(it->ao);
        if (nd != 0) {
            it->factors[mit->nd-1] = 1;
        }
        for (j = 0; j < mit->nd; j++) {
            it->dims_m1[j] = mit->dimensions[j] - 1;
            k = j + nd - mit->nd;
            /*
             * 如果此维度是添加的或底层数组的形状为1
             */
            if ((k < 0) ||
                PyArray_DIMS(it->ao)[k] != mit->dimensions[j]) {
                it->contiguous = 0;
                it->strides[j] = 0;
            }
            else {
                it->strides[j] = PyArray_STRIDES(it->ao)[k];
            }
            it->backstrides[j] = it->strides[j] * it->dims_m1[j];
            if (j > 0)
                it->factors[mit->nd-j-1] =
                    it->factors[mit->nd-j] * mit->dimensions[mit->nd-j];
        }
        PyArray_ITER_RESET(it);
    }
    return 0;
/*
 * 返回一个错误信息对象,指示传递的参数数量不正确。
 * 参数数量需要至少为0且最多为NPY_MAXARGS个数组对象。
 */
static inline PyObject*
multiiter_wrong_number_of_args(void)
{
    return PyErr_Format(PyExc_ValueError,
                        "Need at least 0 and at most %d "
                        "array objects.", NPY_MAXARGS);
}

/*
 * PyArrayMultiIterObject 构造函数的通用实现。
 * 创建一个 PyArrayMultiIterObject 对象,用于迭代多个数组。
 */
static PyObject*
multiiter_new_impl(int n_args, PyObject **args)
{
    PyArrayMultiIterObject *multi;
    int i;

    // 分配 PyArrayMultiIterObject 结构的内存空间
    multi = PyArray_malloc(sizeof(PyArrayMultiIterObject));
    if (multi == NULL) {
        return PyErr_NoMemory();
    }
    // 初始化 multi 对象,设置其类型为 PyArrayMultiIter_Type
    PyObject_Init((PyObject *)multi, &PyArrayMultiIter_Type);
    multi->numiter = 0;

    for (i = 0; i < n_args; ++i) {
        PyObject *obj = args[i];
        PyObject *arr;
        PyArrayIterObject *it;

        // 如果 obj 是 PyArrayMultiIterObject 类型的实例
        if (PyObject_IsInstance(obj, (PyObject *)&PyArrayMultiIter_Type)) {
            PyArrayMultiIterObject *mit = (PyArrayMultiIterObject *)obj;
            int j;

            // 检查将要添加的迭代器数量是否超过 NPY_MAXARGS
            if (multi->numiter + mit->numiter > NPY_MAXARGS) {
                multiiter_wrong_number_of_args();
                goto fail;
            }
            // 将 mit 中的每个迭代器添加到 multi 中
            for (j = 0; j < mit->numiter; ++j) {
                arr = (PyObject *)mit->iters[j]->ao;
                it = (PyArrayIterObject *)PyArray_IterNew(arr);
                if (it == NULL) {
                    goto fail;
                }
                multi->iters[multi->numiter++] = it;
            }
        }
        // 如果 multi 中迭代器的数量还未达到 NPY_MAXARGS,且 obj 可以转换为数组对象
        else if (multi->numiter < NPY_MAXARGS) {
            arr = PyArray_FromAny(obj, NULL, 0, 0, 0, NULL);
            if (arr == NULL) {
                goto fail;
            }
            it = (PyArrayIterObject *)PyArray_IterNew(arr);
            Py_DECREF(arr);
            if (it == NULL) {
                goto fail;
            }
            multi->iters[multi->numiter++] = it;
        }
        else {
            multiiter_wrong_number_of_args();
            goto fail;
        }
    }

    // 检查是否成功添加了迭代器
    if (multi->numiter < 0) {
        multiiter_wrong_number_of_args();
        goto fail;
    }
    // 对 multi 进行广播处理
    if (PyArray_Broadcast(multi) < 0) {
        goto fail;
    }
    // 重置 multi 的多重迭代器状态
    PyArray_MultiIter_RESET(multi);

    return (PyObject *)multi;

fail:
    // 在失败时释放 multi 对象
    Py_DECREF(multi);

    return NULL;
}

/*NUMPY_API
 * 从 Python 对象数组和任何额外数组中获取 MultiIterator
 *
 * PyObject **mps - PyObjects 数组
 * int n - 数组中的 PyObjects 数量
 * int nadd - 要包含在迭代器中的额外数组数量
 *
 * 返回一个 MultiIterator 对象。
 */
NPY_NO_EXPORT PyObject*
PyArray_MultiIterFromObjects(PyObject **mps, int n, int nadd, ...)
{
    PyObject *args_impl[NPY_MAXARGS];
    int ntot = n + nadd;
    int i;
    va_list va;

    // 检查总参数数量是否在合理范围内
    if ((ntot > NPY_MAXARGS) || (ntot < 0)) {
        return multiiter_wrong_number_of_args();
    }

    // 复制 mps 数组中的 Python 对象到 args_impl 中
    for (i = 0; i < n; ++i) {
        args_impl[i] = mps[i];
    }

    // 处理可变参数列表,将其添加到 args_impl 中
    va_start(va, nadd);
    for (; i < ntot; ++i) {
        args_impl[i] = va_arg(va, PyObject *);
    }
    va_end(va);

    // 调用 multiiter_new_impl 函数创建 MultiIterator 对象并返回
    return multiiter_new_impl(ntot, args_impl);
}
/*NUMPY_API
 * Get MultiIterator,
 */
/* 定义 PyArray_MultiIterNew 函数,返回 PyObject 指针类型 */
NPY_NO_EXPORT PyObject*
PyArray_MultiIterNew(int n, ...)
{
    /* 定义存储 PyObject 指针的数组 */
    PyObject *args_impl[NPY_MAXARGS];
    /* 定义循环计数器 */
    int i;
    /* 定义 va_list 变量 */
    va_list va;

    /* 如果参数个数超过 NPY_MAXARGS 或小于 0,则调用 multiiter_wrong_number_of_args 函数返回错误信息 */
    if ((n > NPY_MAXARGS) || (n < 0)) {
        return multiiter_wrong_number_of_args();
    }

    /* 开始使用可变参数列表 */
    va_start(va, n);
    /* 将可变参数列表中的参数依次存入 args_impl 数组中 */
    for (i = 0; i < n; ++i) {
        args_impl[i] = va_arg(va, PyObject *);
    }
    /* 结束可变参数列表的使用 */
    va_end(va);

    /* 调用 multiiter_new_impl 函数,返回多迭代器对象的 PyObject 指针 */
    return multiiter_new_impl(n, args_impl);
}

/* 定义 arraymultiter_new 函数 */
static PyObject*
arraymultiter_new(PyTypeObject *NPY_UNUSED(subtype), PyObject *args,
                  PyObject *kwds)
{
    /* 定义返回值、快速序列和序列长度 */
    PyObject *ret, *fast_seq;
    Py_ssize_t n;

    /* 如果关键字参数不为空且大于 0,抛出 ValueError 异常 */
    if (kwds != NULL && PyDict_Size(kwds) > 0) {
        PyErr_SetString(PyExc_ValueError,
                        "keyword arguments not accepted.");
        return NULL;
    }

    /* 将传入的参数 args 转换为快速序列 fast_seq */
    fast_seq = PySequence_Fast(args, "");  // needed for pypy
    /* 如果转换失败,返回 NULL */
    if (fast_seq == NULL) {
        return NULL;
    }
    /* 获取快速序列的长度 */
    n = PySequence_Fast_GET_SIZE(fast_seq);
    /* 如果长度大于 NPY_MAXARGS,释放 fast_seq 并返回错误信息 */
    if (n > NPY_MAXARGS) {
        Py_DECREF(fast_seq);
        return multiiter_wrong_number_of_args();
    }
    /* 调用 multiiter_new_impl 函数,返回多迭代器对象的 PyObject 指针 */
    ret = multiiter_new_impl(n, PySequence_Fast_ITEMS(fast_seq));
    /* 释放 fast_seq 对象 */
    Py_DECREF(fast_seq);
    return ret;
}

/* 定义 arraymultiter_next 函数 */
static PyObject *
arraymultiter_next(PyArrayMultiIterObject *multi)
{
    /* 定义返回值、迭代器数目和循环计数器 */
    PyObject *ret;
    int i, n;

    /* 获取迭代器的数目 */
    n = multi->numiter;
    /* 创建一个元组对象作为返回值 */
    ret = PyTuple_New(n);
    /* 如果创建失败,返回 NULL */
    if (ret == NULL) {
        return NULL;
    }
    /* 如果 multi->index 小于 multi->size */
    if (multi->index < multi->size) {
        /* 遍历迭代器数组 */
        for (i = 0; i < n; i++) {
            /* 获取当前迭代器对象 */
            PyArrayIterObject *it=multi->iters[i];
            /* 将迭代器指向的数据转换为标量对象,存入元组中 */
            PyTuple_SET_ITEM(ret, i,
                             PyArray_ToScalar(it->dataptr, it->ao));
            /* 移动迭代器到下一个位置 */
            PyArray_ITER_NEXT(it);
        }
        /* 增加 multi 的索引值 */
        multi->index++;
        /* 返回元组对象 */
        return ret;
    }
    /* 如果 multi->index 大于等于 multi->size,释放 ret 对象并返回 NULL */
    Py_DECREF(ret);
    return NULL;
}

/* 定义 arraymultiter_dealloc 函数 */
static void
arraymultiter_dealloc(PyArrayMultiIterObject *multi)
{
    /* 定义循环计数器 */
    int i;

    /* 释放迭代器数组中的每一个迭代器对象 */
    for (i = 0; i < multi->numiter; i++) {
        Py_XDECREF(multi->iters[i]);
    }
    /* 释放 multi 对象内存 */
    Py_TYPE(multi)->tp_free((PyObject *)multi);
}

/* 定义 arraymultiter_size_get 函数 */
static PyObject *
arraymultiter_size_get(PyArrayMultiIterObject *self, void *NPY_UNUSED(ignored))
{
    /* 返回 self 对象的 size 属性 */
    return PyArray_PyIntFromIntp(self->size);
}

/* 定义 arraymultiter_index_get 函数 */
static PyObject *
arraymultiter_index_get(PyArrayMultiIterObject *self, void *NPY_UNUSED(ignored))
{
    /* 返回 self 对象的 index 属性 */
    return PyArray_PyIntFromIntp(self->index);
}

/* 定义 arraymultiter_shape_get 函数 */
static PyObject *
arraymultiter_shape_get(PyArrayMultiIterObject *self, void *NPY_UNUSED(ignored))
{
    /* 返回 self 对象的 dimensions 属性 */
    return PyArray_IntTupleFromIntp(self->nd, self->dimensions);
}

/* 定义 arraymultiter_iters_get 函数 */
static PyObject *
arraymultiter_iters_get(PyArrayMultiIterObject *self, void *NPY_UNUSED(ignored))
{
    /* 返回一个元组对象,包含 self 对象的所有迭代器 */
    PyObject *res;
    int i, n;

    /* 获取迭代器的数目 */
    n = self->numiter;
    /* 创建一个包含 n 个元素的元组对象 */
    res = PyTuple_New(n);
    /* 如果创建失败,返回 NULL */
    if (res == NULL) {
        return res;
    }
    /* 遍历 self 对象的迭代器数组,将每个迭代器对象添加到元组中 */
    for (i = 0; i < n; i++) {
        Py_INCREF(self->iters[i]);
        PyTuple_SET_ITEM(res, i, (PyObject *)self->iters[i]);
    }
    /* 返回包含迭代器的元组对象 */
    return res;
}

/* 定义 arraymultiter_getsetlist 数组,包含 size 属性的 getter 函数 */
static PyGetSetDef arraymultiter_getsetlist[] = {
    {"size",
        (getter)arraymultiter_size_get,
        NULL,
        NULL, NULL},
    {"index",
        // 键名为 "index",对应的 getter 函数为 arraymultiter_index_get
        (getter)arraymultiter_index_get,
        // setter 为 NULL
        NULL,
        // docstring 为 NULL
        NULL, NULL},
    {"shape",
        // 键名为 "shape",对应的 getter 函数为 arraymultiter_shape_get
        (getter)arraymultiter_shape_get,
        // setter 为 NULL
        NULL,
        // docstring 为 NULL
        NULL, NULL},
    {"iters",
        // 键名为 "iters",对应的 getter 函数为 arraymultiter_iters_get
        (getter)arraymultiter_iters_get,
        // setter 为 NULL
        NULL,
        // docstring 为 NULL
        NULL, NULL},
    {NULL, NULL, NULL, NULL, NULL},
        // 最后一行为 NULL 结束符
};

static PyMemberDef arraymultiter_members[] = {
    {"numiter",
        T_INT,
        offsetof(PyArrayMultiIterObject, numiter),
        READONLY, NULL},
    {"nd",
        T_INT,
        offsetof(PyArrayMultiIterObject, nd),
        READONLY, NULL},
    {"ndim",
        T_INT,
        offsetof(PyArrayMultiIterObject, nd),
        READONLY, NULL},
    {NULL, 0, 0, 0, NULL},
};

static PyObject *
arraymultiter_reset(PyArrayMultiIterObject *self, PyObject *args)
{
    // 解析参数元组,如果解析失败则返回 NULL
    if (!PyArg_ParseTuple(args, "")) {
        return NULL;
    }
    // 调用 NumPy C API 函数 PyArray_MultiIter_RESET 重置多重迭代器对象
    PyArray_MultiIter_RESET(self);
    // 返回 Python 中的 None 对象
    Py_RETURN_NONE;
}

static PyMethodDef arraymultiter_methods[] = {
    // reset 方法的定义
    {"reset",
        (PyCFunction) arraymultiter_reset,
        METH_VARARGS, NULL},
    {NULL, NULL, 0, NULL},      /* sentinel */
};

NPY_NO_EXPORT PyTypeObject PyArrayMultiIter_Type = {
    // PyArrayMultiIter_Type 对象的类型定义
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "numpy.broadcast",   // 对象类型名称
    .tp_basicsize = sizeof(PyArrayMultiIterObject),   // 基本大小
    .tp_dealloc = (destructor)arraymultiter_dealloc,  // 析构函数
    .tp_flags = Py_TPFLAGS_DEFAULT,   // 默认标志
    .tp_iternext = (iternextfunc)arraymultiter_next, // 迭代下一个函数
    .tp_methods = arraymultiter_methods,   // 方法列表
    .tp_members = arraymultiter_members,   // 成员列表
    .tp_getset = arraymultiter_getsetlist, // 获取和设置方法列表
    .tp_new = arraymultiter_new,   // 新建对象的方法
};

/*========================= Neighborhood iterator ======================*/

static void neighiter_dealloc(PyArrayNeighborhoodIterObject* iter);

static char* _set_constant(PyArrayNeighborhoodIterObject* iter,
        PyArrayObject *fill)
{
    char *ret;
    PyArrayIterObject *ar = iter->_internal_iter;
    int storeflags, st;

    // 分配内存给 ret,大小为数组元素的大小
    ret = PyDataMem_NEW(PyArray_ITEMSIZE(ar->ao));
    if (ret == NULL) {
        // 分配内存失败,设置内存错误并返回 NULL
        PyErr_SetNone(PyExc_MemoryError);
        return NULL;
    }

    if (PyArray_ISOBJECT(ar->ao)) {
        // 如果数组元素是对象类型,则复制填充数组中的 PyObject* 数据到 ret
        memcpy(ret, PyArray_DATA(fill), sizeof(PyObject*));
        // 增加引用计数
        Py_INCREF(*(PyObject**)ret);
    } else {
        /* 非对象类型 */

        // 存储原始标志
        storeflags = PyArray_FLAGS(ar->ao);
        // 设置数组行为标志
        PyArray_ENABLEFLAGS(ar->ao, NPY_ARRAY_BEHAVED);
        // 设置数组元素为 fill
        st = PyArray_SETITEM(ar->ao, ret, (PyObject*)fill);
        // 恢复原始标志
        ((PyArrayObject_fields *)ar->ao)->flags = storeflags;

        if (st < 0) {
            // 设置数组元素失败,释放内存并返回 NULL
            PyDataMem_FREE(ret);
            return NULL;
        }
    }

    return ret;
}

#define _INF_SET_PTR(c) \
    bd = coordinates[c] + p->coordinates[c]; \
    if (bd < p->limits[c][0] || bd > p->limits[c][1]) { \
        return niter->constant; \
    } \
    _coordinates[c] = bd;

/* 根据当前坐标设置数据指针 */
static char*
get_ptr_constant(PyArrayIterObject* _iter, const npy_intp *coordinates)
{
    int i;
    npy_intp bd, _coordinates[NPY_MAXDIMS];
    PyArrayNeighborhoodIterObject *niter = (PyArrayNeighborhoodIterObject*)_iter;
    PyArrayIterObject *p = niter->_internal_iter;

    for(i = 0; i < niter->nd; ++i) {
        _INF_SET_PTR(i)
    }

    // 调用 translate 方法返回数据指针
    return p->translate(p, _coordinates);
}
#undef _INF_SET_PTR

#define _NPY_IS_EVEN(x) ((x) % 2 == 0)
/*
 * For an array x of dimension n, and given index i, returns j, 0 <= j < n
 * such as x[i] = x[j], with x assumed to be mirrored. For example, for x =
 * {1, 2, 3} (n = 3)
 *
 * index -5 -4 -3 -2 -1 0 1 2 3 4 5 6
 * value  2  3  3  2  1 1 2 3 3 2 1 1
 *
 * __npy_pos_remainder(4, 3) will return 1, because x[4] = x[1]
 */
static inline npy_intp
__npy_pos_remainder(npy_intp i, npy_intp n)
{
    npy_intp k, l, j;

    /* Mirror i such that it is guaranteed to be positive */
    if (i < 0) {
        i = - i - 1;
    }

    /* Compute k and l such that i = k * n + l, 0 <= l < k */
    k = i / n;
    l = i - k * n;

    if (_NPY_IS_EVEN(k)) {
        j = l;
    } else {
        j = n - 1 - l;
    }
    return j;
}
#undef _NPY_IS_EVEN

/*
 * Macro to set _coordinates[c] using mirrored indexing based on bounds
 * and current coordinates for neighborhood iteration.
 */
#define _INF_SET_PTR_MIRROR(c) \
    lb = p->limits[c][0]; \
    bd = coordinates[c] + p->coordinates[c] - lb; \
    _coordinates[c] = lb + __npy_pos_remainder(bd, p->limits_sizes[c]);

/*
 * Sets the data pointer (_coordinates) based on mirrored indexing for
 * neighborhood iteration.
 */
static char*
get_ptr_mirror(PyArrayIterObject* _iter, const npy_intp *coordinates)
{
    int i;
    npy_intp bd, _coordinates[NPY_MAXDIMS], lb;
    PyArrayNeighborhoodIterObject *niter = (PyArrayNeighborhoodIterObject*)_iter;
    PyArrayIterObject *p = niter->_internal_iter;

    for(i = 0; i < niter->nd; ++i) {
        _INF_SET_PTR_MIRROR(i)
    }

    return p->translate(p, _coordinates);
}
#undef _INF_SET_PTR_MIRROR

/*
 * Compute l such that i = k * n + l, 0 <= l < |k|
 */
static inline npy_intp
__npy_euclidean_division(npy_intp i, npy_intp n)
{
    npy_intp l;

    l = i % n;
    if (l < 0) {
        l += n;
    }
    return l;
}

/*
 * Macro to set _coordinates[c] using circular indexing based on bounds
 * and current coordinates for neighborhood iteration.
 */
#define _INF_SET_PTR_CIRCULAR(c) \
    lb = p->limits[c][0]; \
    bd = coordinates[c] + p->coordinates[c] - lb; \
    _coordinates[c] = lb + __npy_euclidean_division(bd, p->limits_sizes[c]);

/*
 * Sets the data pointer (_coordinates) based on circular indexing for
 * neighborhood iteration.
 */
static char*
get_ptr_circular(PyArrayIterObject* _iter, const npy_intp *coordinates)
{
    int i;
    npy_intp bd, _coordinates[NPY_MAXDIMS], lb;
    PyArrayNeighborhoodIterObject *niter = (PyArrayNeighborhoodIterObject*)_iter;
    PyArrayIterObject *p = niter->_internal_iter;

    for(i = 0; i < niter->nd; ++i) {
        _INF_SET_PTR_CIRCULAR(i)
    }
    return p->translate(p, _coordinates);
}
#undef _INF_SET_PTR_CIRCULAR

/*
 * Create a new neighborhood iterator object.
 */
/*NUMPY_API
 * A Neighborhood Iterator object.
 */
NPY_NO_EXPORT PyObject*
PyArray_NeighborhoodIterNew(PyArrayIterObject *x, const npy_intp *bounds,
                            int mode, PyArrayObject* fill)
{
    int i;
    PyArrayNeighborhoodIterObject *ret;

    ret = PyArray_malloc(sizeof(*ret));
    if (ret == NULL) {
        return NULL;
    }
    PyObject_Init((PyObject *)ret, &PyArrayNeighborhoodIter_Type);

    Py_INCREF(x->ao);  /* PyArray_RawIterBaseInit steals a reference */
    PyArray_RawIterBaseInit((PyArrayIterObject*)ret, x->ao);
    Py_INCREF(x);
    ret->_internal_iter = x;

    ret->nd = PyArray_NDIM(x->ao);

    /* Additional initialization and setup code continues beyond this point */
    for (i = 0; i < ret->nd; ++i) {
        ret->dimensions[i] = PyArray_DIMS(x->ao)[i];
    }


    /* 设置返回结构体中的维度信息为输入数组的维度信息 */
    ret->dimensions[i] = PyArray_DIMS(x->ao)[i];



    /* 计算邻域的大小并复制形状 */
    ret->size = 1;
    for (i = 0; i < ret->nd; ++i) {
        ret->bounds[i][0] = bounds[2 * i];
        ret->bounds[i][1] = bounds[2 * i + 1];
        ret->size *= (ret->bounds[i][1] - ret->bounds[i][0]) + 1;

        /* limits 用于跟踪邻域的有效范围:如果邻域的边界超出数组范围,则 limits 等于 boundaries。
         * 相反,如果边界严格在数组内部,则 limits 对应于数组范围。例如,对于数组 [1, 2, 3],
         * 如果边界是 [-1, 3],则 limits 是 [-1, 3];但如果边界是 [1, 2],则 limits 是 [0, 2]。
         *
         * 这在叠加在此迭代器之上的邻域迭代器中使用 */
        ret->limits[i][0] = ret->bounds[i][0] < 0 ? ret->bounds[i][0] : 0;
        ret->limits[i][1] = ret->bounds[i][1] >= ret->dimensions[i] - 1 ?
                            ret->bounds[i][1] :
                            ret->dimensions[i] - 1;
        ret->limits_sizes[i] = (ret->limits[i][1] - ret->limits[i][0]) + 1;
    }


    /* 计算邻域的大小并复制形状 */
    ret->size = 1;
    for (i = 0; i < ret->nd; ++i) {
        /* 设置邻域边界 */
        ret->bounds[i][0] = bounds[2 * i];
        ret->bounds[i][1] = bounds[2 * i + 1];
        /* 计算邻域大小 */
        ret->size *= (ret->bounds[i][1] - ret->bounds[i][0]) + 1;

        /* limits 用于跟踪邻域的有效范围 */
        ret->limits[i][0] = ret->bounds[i][0] < 0 ? ret->bounds[i][0] : 0;
        ret->limits[i][1] = ret->bounds[i][1] >= ret->dimensions[i] - 1 ?
                            ret->bounds[i][1] :
                            ret->dimensions[i] - 1;
        ret->limits_sizes[i] = (ret->limits[i][1] - ret->limits[i][0]) + 1;
    }



    switch (mode) {
        case NPY_NEIGHBORHOOD_ITER_ZERO_PADDING:
            ret->constant = PyArray_Zero(x->ao);
            ret->mode = mode;
            ret->translate = &get_ptr_constant;
            break;
        case NPY_NEIGHBORHOOD_ITER_ONE_PADDING:
            ret->constant = PyArray_One(x->ao);
            ret->mode = mode;
            ret->translate = &get_ptr_constant;
            break;
        case NPY_NEIGHBORHOOD_ITER_CONSTANT_PADDING:
            /* _set_constant 返回值中的新引用,如果数组对象 */
            assert(PyArray_EquivArrTypes(x->ao, fill) == NPY_TRUE);
            ret->constant = _set_constant(ret, fill);
            if (ret->constant == NULL) {
                goto clean_x;
            }
            ret->mode = mode;
            ret->translate = &get_ptr_constant;
            break;
        case NPY_NEIGHBORHOOD_ITER_MIRROR_PADDING:
            ret->mode = mode;
            ret->constant = NULL;
            ret->translate = &get_ptr_mirror;
            break;
        case NPY_NEIGHBORHOOD_ITER_CIRCULAR_PADDING:
            ret->mode = mode;
            ret->constant = NULL;
            ret->translate = &get_ptr_circular;
            break;
        default:
            PyErr_SetString(PyExc_ValueError, "Unsupported padding mode");
            goto clean_x;
    }


    /* 根据不同的填充模式进行设置 */
    switch (mode) {
        case NPY_NEIGHBORHOOD_ITER_ZERO_PADDING:
            /* 使用零填充模式 */
            ret->constant = PyArray_Zero(x->ao);
            ret->mode = mode;
            ret->translate = &get_ptr_constant;
            break;
        case NPY_NEIGHBORHOOD_ITER_ONE_PADDING:
            /* 使用一填充模式 */
            ret->constant = PyArray_One(x->ao);
            ret->mode = mode;
            ret->translate = &get_ptr_constant;
            break;
        case NPY_NEIGHBORHOOD_ITER_CONSTANT_PADDING:
            /* 常数填充模式,_set_constant 返回值中的新引用 */
            assert(PyArray_EquivArrTypes(x->ao, fill) == NPY_TRUE);
            ret->constant = _set_constant(ret, fill);
            if (ret->constant == NULL) {
                goto clean_x;
            }
            ret->mode = mode;
            ret->translate = &get_ptr_constant;
            break;
        case NPY_NEIGHBORHOOD_ITER_MIRROR_PADDING:
            /* 镜像填充模式 */
            ret->mode = mode;
            ret->constant = NULL;
            ret->translate = &get_ptr_mirror;
            break;
        case NPY_NEIGHBORHOOD_ITER_CIRCULAR_PADDING:
            /* 循环填充模式 */
            ret->mode = mode;
            ret->constant = NULL;
            ret->translate = &get_ptr_circular;
            break;
        default:
            /* 不支持的填充模式 */
            PyErr_SetString(PyExc_ValueError, "Unsupported padding mode");
            goto clean_x;
    }



    /*
     * XXX: we force x iterator to be non contiguous because we need
     * coordinates... Modifying the iterator here is not great
     */
    x->contiguous = 0;


    /* 强制 x 迭代器为非连续,因为我们需要坐标... 在这里修改迭代器并不是最佳做法 */
    x->contiguous = 0;



    PyArrayNeighborhoodIter_Reset(ret);

    return (PyObject*)ret;


    /* 重置邻域迭代器并返回其 PyObject* 类型的指针 */
    PyArrayNeighborhoodIter_Reset(ret);

    return (PyObject*)ret;
// 释放 clean_x 函数中 ret 结构体的内部迭代器资源
Py_DECREF(ret->_internal_iter);
// 调用 array_iter_base_dealloc 函数释放 ret 结构体的基类迭代器资源
array_iter_base_dealloc((PyArrayIterObject*)ret);
// 释放 ret 结构体本身的内存资源
PyArray_free((PyArrayObject*)ret);
// 返回空指针表示操作失败
return NULL;
}

// 释放 PyArrayNeighborhoodIterObject 结构体的资源
static void neighiter_dealloc(PyArrayNeighborhoodIterObject* iter)
{
    // 如果迭代器模式是常量填充模式
    if (iter->mode == NPY_NEIGHBORHOOD_ITER_CONSTANT_PADDING) {
        // 如果数组对象是对象数组,则释放常量指针指向的对象
        if (PyArray_ISOBJECT(iter->_internal_iter->ao)) {
            Py_DECREF(*(PyObject**)iter->constant);
        }
    }
    // 释放常量数组的内存资源
    PyDataMem_FREE(iter->constant);
    // 释放内部迭代器资源
    Py_DECREF(iter->_internal_iter);

    // 调用 array_iter_base_dealloc 函数释放 iter 结构体的基类迭代器资源
    array_iter_base_dealloc((PyArrayIterObject*)iter);
    // 释放 iter 结构体本身的内存资源
    PyArray_free((PyArrayObject*)iter);
}

// 定义 PyArrayNeighborhoodIter_Type 类型的静态属性
NPY_NO_EXPORT PyTypeObject PyArrayNeighborhoodIter_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    // 类型名称为 "numpy.neigh_internal_iter"
    .tp_name = "numpy.neigh_internal_iter",
    // 类型对象的基本大小为 PyArrayNeighborhoodIterObject 结构体大小
    .tp_basicsize = sizeof(PyArrayNeighborhoodIterObject),
    // 设置析构函数为 neighiter_dealloc 函数
    .tp_dealloc = (destructor)neighiter_dealloc,
    // 设置默认标志位
    .tp_flags = Py_TPFLAGS_DEFAULT,
};

.\numpy\numpy\_core\src\multiarray\iterators.h

#ifndef NUMPY_CORE_SRC_MULTIARRAY_ITERATORS_H_
#define NUMPY_CORE_SRC_MULTIARRAY_ITERATORS_H_

# 定义了 NUMPY_CORE_SRC_MULTIARRAY_ITERATORS_H_ 宏,用于防止头文件重复包含

NPY_NO_EXPORT PyObject
*iter_subscript(PyArrayIterObject *, PyObject *);

# 声明了一个名为 iter_subscript 的函数,接受一个 PyArrayIterObject 指针和一个 PyObject 指针作为参数,返回一个 PyObject 指针

NPY_NO_EXPORT int
iter_ass_subscript(PyArrayIterObject *, PyObject *, PyObject *);

# 声明了一个名为 iter_ass_subscript 的函数,接受一个 PyArrayIterObject 指针和两个 PyObject 指针作为参数,返回一个整型值

NPY_NO_EXPORT void
PyArray_RawIterBaseInit(PyArrayIterObject *it, PyArrayObject *ao);

# 声明了一个名为 PyArray_RawIterBaseInit 的函数,接受一个 PyArrayIterObject 指针和一个 PyArrayObject 指针作为参数,返回空值

#endif  /* NUMPY_CORE_SRC_MULTIARRAY_ITERATORS_H_ */

# 结束了条件编译指令,结束了头文件的内容

.\numpy\numpy\_core\src\multiarray\legacy_dtype_implementation.c

/*
 * 此部分代码定义了一些用于比较和判断旧版数据类型的函数和宏。
 * 这些函数和宏主要用于处理旧版数据类型,可能在将来被弃用和移除。
 */

#define NPY_NO_DEPRECATED_API NPY_API_VERSION
#define _MULTIARRAYMODULE

#include "numpy/arrayobject.h"
#include "scalartypes.h"
#include "_datetime.h"
#include "datetime_strings.h"
#include "can_cast_table.h"
#include "convert_datatype.h"
#include "dtypemeta.h"

#include "legacy_dtype_implementation.h"

/*
 * 比较两个数据类型的字段字典是否相等。
 * 如果两个描述符的字段类型和字段名称相等且顺序相同,则返回1,否则返回0。
 */
static int
_equivalent_fields(_PyArray_LegacyDescr *type1, _PyArray_LegacyDescr *type2) {

    int val;

    if (type1->fields == type2->fields && type1->names == type2->names) {
        return 1;
    }
    if (type1->fields == NULL || type2->fields == NULL) {
        return 0;
    }

    val = PyObject_RichCompareBool(type1->fields, type2->fields, Py_EQ);
    if (val != 1 || PyErr_Occurred()) {
        PyErr_Clear();
        return 0;
    }

    val = PyObject_RichCompareBool(type1->names, type2->names, Py_EQ);
    if (val != 1 || PyErr_Occurred()) {
        PyErr_Clear();
        return 0;
    }

    return 1;
}

/*
 * 比较两个数据类型的子数组数据是否相等。
 * 如果相等则返回1,否则返回0。
 */
static int
_equivalent_subarrays(PyArray_ArrayDescr *sub1, PyArray_ArrayDescr *sub2)
{
    int val;

    if (sub1 == sub2) {
        return 1;
    }
    if (sub1 == NULL || sub2 == NULL) {
        return 0;
    }

    val = PyObject_RichCompareBool(sub1->shape, sub2->shape, Py_EQ);
    if (val != 1 || PyErr_Occurred()) {
        PyErr_Clear();
        return 0;
    }

    return PyArray_EquivTypes(sub1->base, sub2->base);
}

/*
 * 判断两个数据描述符是否等价。
 * 如果是旧版数据类型且各种条件满足则返回NPY_TRUE,否则返回NPY_FALSE。
 */
static unsigned char
PyArray_LegacyEquivTypes(PyArray_Descr *type1, PyArray_Descr *type2)
{
    int type_num1, type_num2, size1, size2;

    if (type1 == type2) {
        return NPY_TRUE;
    }
    if (!PyDataType_ISLEGACY(type1) || !PyDataType_ISLEGACY(type2)) {
        return NPY_FALSE;
    }

    type_num1 = type1->type_num;
    type_num2 = type2->type_num;
    size1 = type1->elsize;
    size2 = type2->elsize;

    if (size1 != size2) {
        return NPY_FALSE;
    }
    if (PyArray_ISNBO(type1->byteorder) != PyArray_ISNBO(type2->byteorder)) {
        return NPY_FALSE;
    }
    if (PyDataType_SUBARRAY(type1) || PyDataType_SUBARRAY(type2)) {
        return ((type_num1 == type_num2)
                && _equivalent_subarrays(PyDataType_SUBARRAY(type1), PyDataType_SUBARRAY(type2)));
    }
    if (type_num1 == NPY_VOID || type_num2 == NPY_VOID) {
        return ((type_num1 == type_num2) && _equivalent_fields(
                    (_PyArray_LegacyDescr *)type1, (_PyArray_LegacyDescr *)type2));
    }
    # 如果 type_num1 或 type_num2 是 NPY_DATETIME 或 NPY_TIMEDELTA 类型之一,则执行以下操作
    if (type_num1 == NPY_DATETIME
        || type_num1 == NPY_TIMEDELTA
        || type_num2 == NPY_DATETIME
        || type_num2 == NPY_TIMEDELTA) {
        # 如果 type_num1 和 type_num2 的类型相同,并且具有等效的日期时间元数据,则返回真
        return ((type_num1 == type_num2)
                && has_equivalent_datetime_metadata(type1, type2));
    }
    
    # 如果不满足上述条件,则比较 type1 和 type2 的 kind 属性是否相同,然后返回结果
    return type1->kind == type2->kind;
/*
 * 比较两个类型描述符的等价性。
 *
 * 如果 typenum1 和 typenum2 相等,则返回 NPY_SUCCEED;否则返回 NPY_FAIL。
 */
static unsigned char
PyArray_LegacyEquivTypenums(int typenum1, int typenum2)
{
    PyArray_Descr *d1, *d2;
    npy_bool ret;

    // 检查 typenum1 和 typenum2 是否相等
    if (typenum1 == typenum2) {
        return NPY_SUCCEED;
    }

    // 获取 typenum1 和 typenum2 对应的类型描述符
    d1 = PyArray_DescrFromType(typenum1);
    d2 = PyArray_DescrFromType(typenum2);

    // 判断两个类型描述符是否等价
    ret = PyArray_LegacyEquivTypes(d1, d2);

    // 释放类型描述符的引用
    Py_DECREF(d1);
    Py_DECREF(d2);

    return ret;
}


/*
 * 检查是否可以安全地从一个类型转换到另一个类型。
 *
 * 如果 fromtype 和 totype 相等,则返回 1;否则根据类型转换表格判断是否可以安全转换。
 * 如果可以安全转换,则返回 1;否则返回 0。
 */
static int
PyArray_LegacyCanCastSafely(int fromtype, int totype)
{
    PyArray_Descr *from;

    /* 快速查找小类型编号的表格 */
    if ((unsigned int)fromtype < NPY_NTYPES_LEGACY &&
        (unsigned int)totype < NPY_NTYPES_LEGACY) {
        return _npy_can_cast_safely_table[fromtype][totype];
    }

    /* 判断是否同一类型 */
    if (fromtype == totype) {
        return 1;
    }

    // 获取 fromtype 对应的类型描述符
    from = PyArray_DescrFromType(fromtype);

    /*
     * cancastto 是一个以 NPY_NOTYPE 结尾的 C 整型数组,表示该数据类型可以安全转换的目标类型。
     * 遍历数组,查找是否存在可以安全转换到 totype 的目标类型。
     */
    if (PyDataType_GetArrFuncs(from)->cancastto) {
        int *curtype = PyDataType_GetArrFuncs(from)->cancastto;

        while (*curtype != NPY_NOTYPE) {
            if (*curtype++ == totype) {
                Py_DECREF(from);
                return 1;
            }
        }
    }

    // 释放类型描述符的引用
    Py_DECREF(from);
    return 0;
}


/*
 * 检查是否可以安全地将一个类型描述符转换为另一个类型描述符。
 *
 * 根据 from 和 to 的类型描述符,判断是否可以安全转换。
 * 如果可以安全转换,则返回 1;否则返回 0。
 */
static npy_bool
PyArray_LegacyCanCastTo(PyArray_Descr *from, PyArray_Descr *to)
{
    int from_type_num = from->type_num;
    int to_type_num = to->type_num;
    npy_bool ret;

    // 调用 PyArray_LegacyCanCastSafely 函数判断是否可以安全转换
    ret = (npy_bool) PyArray_LegacyCanCastSafely(from_type_num, to_type_num);

    return ret;
}


/*
 * 比较两个字段字典是否可以安全地进行类型转换。
 *
 * 如果 field1 和 field2 相同,则返回 1;
 * 如果 field1 或 field2 为空,则返回 0;
 * 如果 field1 和 field2 中的字段数量不同,则返回 0;
 * 遍历 field1 和 field2 中的每个字段,并比较其类型是否可以安全转换。
 * 如果所有字段都可以安全转换,则返回 1;否则返回 0。
 */
static int
can_cast_fields(PyObject *field1, PyObject *field2, NPY_CASTING casting)
{
    Py_ssize_t ppos;
    PyObject *key;
    PyObject *tuple1, *tuple2;

    // 检查 field1 和 field2 是否是同一个对象
    if (field1 == field2) {
        return 1;
    }

    // 检查 field1 和 field2 是否为空
    if (field1 == NULL || field2 == NULL) {
        return 0;
    }

    // 检查 field1 和 field2 的字段数量是否相同
    if (PyDict_Size(field1) != PyDict_Size(field2)) {
        return 0;
    }

    /* 迭代比较所有字段并检查是否可以安全转换 */
    ppos = 0;
    while (PyDict_Next(field1, &ppos, &key, &tuple1)) {
        // 获取 field2 中与 key 对应的值
        if ((tuple2 = PyDict_GetItem(field2, key)) == NULL) {
            return 0;
        }
        /* 比较字段的 dtype 是否可以安全转换 */
        if (!PyArray_CanCastTypeTo(
                        (PyArray_Descr *)PyTuple_GET_ITEM(tuple1, 0),
                        (PyArray_Descr *)PyTuple_GET_ITEM(tuple2, 0),
                        casting)) {
            return 0;
        }
    }

    return 1;
}


/*
 * 检查是否可以安全地将一个类型描述符转换为另一个类型描述符。
 *
 * 根据 from 和 to 的类型描述符,判断是否可以安全转换。
 * 如果可以安全转换,则返回 NPY_SUCCEED;否则返回 NPY_FAIL。
 */
NPY_NO_EXPORT npy_bool
PyArray_LegacyCanCastTypeTo(PyArray_Descr *from, PyArray_Descr *to,
        NPY_CASTING casting)
{
    // 将 from 和 to 强制转换为 _PyArray_LegacyDescr 结构体指针
    _PyArray_LegacyDescr *lfrom = (_PyArray_LegacyDescr *)from;
    _PyArray_LegacyDescr *lto = (_PyArray_LegacyDescr *)to;

    /*
     * 快速路径:处理相等性和基本类型的情况。
     */
    if (from == to ||
        ((NPY_LIKELY(PyDataType_ISNUMBER(from)) ||
          PyDataType_ISOBJECT(from)) &&
         NPY_LIKELY(from->type_num == to->type_num) &&
         NPY_LIKELY(from->byteorder == to->byteorder))) {
        return 1;
    }
    // 如果 from 或 to 不是遗留数据类型,则返回不可转换
    if (!PyDataType_ISLEGACY(from) || !PyDataType_ISLEGACY(to)) {
        return 0;
    }
    /*
     * 处理包含子数组和字段的情况需要特殊处理。
     */
    if (PyDataType_HASFIELDS(from)) {
        /*
         * 如果 from 是结构化数据类型,则只能在不安全转换的情况下将其转换为非对象类型,
         * 前提是它只有一个字段;递归处理,以防单个字段本身是结构化的。
         */
        if (!PyDataType_HASFIELDS(to) && !PyDataType_ISOBJECT(to)) {
            if (casting == NPY_UNSAFE_CASTING &&
                    PyDict_Size(lfrom->fields) == 1) {
                Py_ssize_t ppos = 0;
                PyObject *tuple;
                PyArray_Descr *field;
                PyDict_Next(lfrom->fields, &ppos, NULL, &tuple);
                field = (PyArray_Descr *)PyTuple_GET_ITEM(tuple, 0);
                /*
                 * 对于子数组,我们需要获取其基础类型;
                 * 由于我们已经在进行不安全转换,可以忽略其形状。
                 */
                if (PyDataType_HASSUBARRAY(field)) {
                    field = PyDataType_SUBARRAY(field)->base;
                }
                return PyArray_LegacyCanCastTypeTo(field, to, casting);
            }
            else {
                return 0;
            }
        }
        /*
         * 从一个结构化数据类型到另一个的转换依赖于字段;
         * 我们将此情况传递给下面的 EquivTypenums 情况处理。
         *
         * TODO: 将上面的部分移到这里?需要检查等价类型编号是否是必需的附加约束。
         *
         * TODO/FIXME: 目前,对于不安全转换,始终允许结构化到结构化的转换;
         * 这是不正确的,但因为 can_cast 下面的处理与 astype 不同步,所以需要;参见 gh-13667。
         */
        if (casting == NPY_UNSAFE_CASTING) {
            return 1;
        }
    }
    else if (PyDataType_HASFIELDS(to)) {
        /*
         * 如果 "from" 是简单数据类型而 "to" 具有字段,则仅不安全转换有效
         * (即使对多个字段也是如此)。
         */
        return casting == NPY_UNSAFE_CASTING;
    }
    /*
     * 对于其他情况,我们暂时认为可以进行不安全转换。
     * FIXME: 确保这里的操作与 "astype" 一致,
     * 即更正确地处理子数组和用户定义的数据类型。
     */
    else if (casting == NPY_UNSAFE_CASTING) {
        // 如果 casting 等于 NPY_UNSAFE_CASTING,则返回 1,表示允许不安全的类型转换
        return 1;
    }
    /*
     * Equivalent simple types can be cast with any value of 'casting', but
     * we need to be careful about structured to structured.
     */
    }
    // 如果允许安全或者同种类的类型转换
    else if (casting == NPY_SAFE_CASTING || casting == NPY_SAME_KIND_CASTING) {
        // 检查是否可以使用旧的 PyArray_LegacyCanCastTo 函数进行转换
        if (PyArray_LegacyCanCastTo(from, to)) {
            return 1; // 可以转换则返回 1
        }
        else if(casting == NPY_SAME_KIND_CASTING) {
            /*
             * Also allow casting from lower to higher kinds, according
             * to the ordering provided by dtype_kind_to_ordering.
             * Some kinds, like datetime, don't fit in the hierarchy,
             * and are special cased as -1.
             */
            int from_order, to_order;

            // 获取源类型和目标类型的类型顺序
            from_order = dtype_kind_to_ordering(from->kind);
            to_order = dtype_kind_to_ordering(to->kind);

            if (to->kind == 'm') {
                // 对于 'm' 类型 (timedelta),直接返回是否源类型在整数类型之前
                int integer_order = dtype_kind_to_ordering('i');
                return (from_order != -1) && (from_order <= integer_order);
            }

            // 一般情况下返回是否源类型顺序在目标类型顺序之前
            return (from_order != -1) && (from_order <= to_order);
        }
        else {
            return 0; // 其他情况返回 0,表示不允许类型转换
        }
    }
    // 如果 casting 设置为 NPY_NO_CASTING 或者 NPY_EQUIV_CASTING
    else {
        return 0; // 返回 0,表示不允许类型转换
    }
}



# 这行代码结束了一个 Python 函数的定义,闭合了函数的代码块

.\numpy\numpy\_core\src\multiarray\legacy_dtype_implementation.h

#ifndef NUMPY_CORE_SRC_MULTIARRAY_LEGACY_DTYPE_IMPLEMENTATION_H_
#define NUMPY_CORE_SRC_MULTIARRAY_LEGACY_DTYPE_IMPLEMENTATION_H_

// 定义了一个条件编译指令,用于避免重复包含同一头文件
// 如果 NUMPY_CORE_SRC_MULTIARRAY_LEGACY_DTYPE_IMPLEMENTATION_H_ 未定义,则编译以下内容

// 导出了一个名为 npy_bool 的非公开符号
// 该符号代表一个布尔类型,用于 NumPy 中的类型转换判断
NPY_NO_EXPORT npy_bool
// 函数声明:用于判断从一个数组描述符(from)是否可以转换为另一个数组描述符(to)
PyArray_LegacyCanCastTypeTo(PyArray_Descr *from, PyArray_Descr *to,
        NPY_CASTING casting);

#endif  /* NUMPY_CORE_SRC_MULTIARRAY_LEGACY_DTYPE_IMPLEMENTATION_H_ */

// 结束条件编译指令,确保该头文件内容只被包含一次

.\numpy\numpy\_core\src\multiarray\mapping.c

/*
 * Define macro to specify the NPY API version without deprecated features
 */
#define NPY_NO_DEPRECATED_API NPY_API_VERSION

/*
 * Define macros to specify modules for multiarray and umath
 */
#define _MULTIARRAYMODULE
#define _UMATHMODULE

/*
 * Clean PY_SSIZE_T type usage to ensure compatibility
 */
#define PY_SSIZE_T_CLEAN

/*
 * Include Python core header files and structmember.h for member descriptors
 */
#include <Python.h>
#include <structmember.h>

/*
 * Include numpy array object and math utility headers
 */
#include "numpy/arrayobject.h"
#include "numpy/npy_math.h"

/*
 * Include necessary custom numpy headers
 */
#include "arrayobject.h"
#include "npy_config.h"
#include "npy_pycompat.h"
#include "npy_import.h"
#include "common.h"
#include "ctors.h"
#include "descriptor.h"
#include "iterators.h"
#include "mapping.h"
#include "lowlevel_strided_loops.h"
#include "item_selection.h"
#include "mem_overlap.h"
#include "array_assign.h"
#include "array_coercion.h"

/*
 * Define code for iterator implementation for nditer until made public
 */
#define NPY_ITERATOR_IMPLEMENTATION_CODE
#include "nditer_impl.h"

/*
 * Include umathmodule header for universal functions in numpy
 */
#include "umathmodule.h"

/*
 * Define constants to indicate presence of different index types in numpy arrays
 */
#define HAS_INTEGER 1
#define HAS_NEWAXIS 2
#define HAS_SLICE 4
#define HAS_ELLIPSIS 8
#define HAS_FANCY 16
#define HAS_BOOL 32
#define HAS_SCALAR_ARRAY 64
#define HAS_0D_BOOL (HAS_FANCY | 128)

/*
 * Implementation of array_length function to provide length of array
 * Supports arrays with non-zero dimensions
 * Throws TypeError for unsized objects (0-dimensional arrays)
 */
NPY_NO_EXPORT Py_ssize_t
array_length(PyArrayObject *self)
{
    if (PyArray_NDIM(self) != 0) {
        return PyArray_DIMS(self)[0]; // Return the length of the first dimension
    } else {
        PyErr_SetString(PyExc_TypeError, "len() of unsized object"); // Raise TypeError for unsized objects
        return -1;
    }
}

/*
 * Helper function for PyArray_MapIterSwapAxes and related functions
 * Generates a tuple for transpose based on specified dimensions
 */
static void
_get_transpose(int fancy_ndim, int consec, int ndim, int getmap, npy_intp *dims)
{
    /*
     * For getting the array the tuple for transpose is
     * (n1,...,n1+n2-1,0,...,n1-1,n1+n2,...,n3-1)
     * n1 is the number of dimensions of the broadcast index array
     * n2 is the number of dimensions skipped at the start
     * n3 is the number of dimensions of the result
     */

    /*
     * For setting the array the tuple for transpose is
     * (n2,...,n1+n2-1,0,...,n2-1,n1+n2,...n3-1)
     */
    int n1 = fancy_ndim;
    int n2 = consec;  // axes to insert at
    int n3 = ndim;

    // Determine the boundary value based on operation type (get or set)
    int bnd = getmap ? n1 : n2;
    int val = bnd;
    int i = 0;

    // Generate the tuple for transpose based on calculated dimensions
    while (val < n1 + n2) {
        dims[i++] = val++;
    }
    val = 0;
    while (val < bnd) {
        dims[i++] = val++;
    }
    val = n1 + n2;
    while (val < n3) {
        dims[i++] = val++;
    }
}
/*
 * Swap the axes to or from their inserted form. MapIter always puts the
 * advanced (array) indices first in the iteration. But if they are
 * consecutive, will insert/transpose them back before returning.
 * This is stored as `mit->consec != 0` (the place where they are inserted)
 * For assignments, the opposite happens: The values to be assigned are
 * transposed (getmap=1 instead of getmap=0). `getmap=0` and `getmap=1`
 * undo the other operation.
 */
NPY_NO_EXPORT void
PyArray_MapIterSwapAxes(PyArrayMapIterObject *mit, PyArrayObject **ret, int getmap)
{
    PyObject *new;
    PyArray_Dims permute;
    npy_intp d[NPY_MAXDIMS];
    PyArrayObject *arr;

    permute.ptr = d;
    permute.len = mit->nd;

    /*
     * arr might not have the right number of dimensions
     * and need to be reshaped first by prepending ones
     */
    arr = *ret;
    if (PyArray_NDIM(arr) != mit->nd) {
        // Calculate dimensions for reshaping arr
        for (int i = 1; i <= PyArray_NDIM(arr); i++) {
            permute.ptr[mit->nd-i] = PyArray_DIMS(arr)[PyArray_NDIM(arr)-i];
        }
        // Prepend ones if necessary
        for (int i = 0; i < mit->nd-PyArray_NDIM(arr); i++) {
            permute.ptr[i] = 1;
        }
        // Reshape arr with the new dimensions
        new = PyArray_Newshape(arr, &permute, NPY_ANYORDER);
        Py_DECREF(arr);
        *ret = (PyArrayObject *)new;
        if (new == NULL) {
            return;
        }
    }

    // Perform transpose operation based on getmap flag
    _get_transpose(mit->nd_fancy, mit->consec, mit->nd, getmap, permute.ptr);

    // Transpose *ret array using permute dimensions
    new = PyArray_Transpose(*ret, &permute);
    Py_DECREF(*ret);
    *ret = (PyArrayObject *)new;
}

static inline void
multi_DECREF(PyObject **objects, npy_intp n)
{
    npy_intp i;
    for (i = 0; i < n; i++) {
        Py_DECREF(objects[i]);
    }
}

/**
 * Unpack a tuple into an array of new references. Returns the number of objects
 * unpacked.
 *
 * Useful if a tuple is being iterated over multiple times, or for a code path
 * that doesn't always want the overhead of allocating a tuple.
 */
static inline npy_intp
unpack_tuple(PyTupleObject *index, PyObject **result, npy_intp result_n)
{
    npy_intp n, i;
    n = PyTuple_GET_SIZE(index);
    if (n > result_n) {
        PyErr_SetString(PyExc_IndexError,
                        "too many indices for array");
        return -1;
    }
    // Unpack tuple into result array and increment references
    for (i = 0; i < n; i++) {
        result[i] = PyTuple_GET_ITEM(index, i);
        Py_INCREF(result[i]);
    }
    return n;
}

/* Unpack a single scalar index, taking a new reference to match unpack_tuple */
static inline npy_intp
unpack_scalar(PyObject *index, PyObject **result, npy_intp NPY_UNUSED(result_n))
{
    // Increment reference for the scalar index
    Py_INCREF(index);
    result[0] = index;
    return 1;
}
/**
 * Turn an index argument into a c-array of `PyObject *`s, one for each index.
 *
 * When a tuple is passed, the tuple elements are unpacked into the buffer.
 * Anything else is handled by unpack_scalar().
 *
 * @param  index     The index object, which may or may not be a tuple. This is
 *                   a borrowed reference.
 * @param  result    An empty buffer of PyObject* to write each index component
 *                   to. The references written are new.
 * @param  result_n  The length of the result buffer
 *
 * @returns          The number of items in `result`, or -1 if an error occurred.
 *                   The entries in `result` at and beyond this index should be
 *                   assumed to contain garbage, even if they were initialized
 *                   to NULL, so are not safe to Py_XDECREF. Use multi_DECREF to
 *                   dispose of them.
 */
NPY_NO_EXPORT npy_intp
unpack_indices(PyObject *index, PyObject **result, npy_intp result_n)
{
    /* It is likely that the logic here can be simplified. See the discussion
     * on https://github.com/numpy/numpy/pull/21029
     */

    /* Fast route for passing a tuple */
    if (PyTuple_CheckExact(index)) {
        // 如果传入的是元组,则调用 unpack_tuple 函数解压元组到 result 中
        return unpack_tuple((PyTupleObject *)index, result, result_n);
    }

    /*
     * Passing a tuple subclass - coerce to the base type. This incurs an
     * allocation, but doesn't need to be a fast path anyway. Note that by
     * calling `PySequence_Tuple`, we ensure that the subclass `__iter__` is
     * called.
     */
    if (PyTuple_Check(index)) {
        // 如果传入的是元组的子类,则强制转换为基础类型元组,并解压到 result 中
        PyTupleObject *tup = (PyTupleObject *) PySequence_Tuple(index);
        if (tup == NULL) {
            return -1;
        }
        npy_intp n = unpack_tuple(tup, result, result_n);
        Py_DECREF(tup);
        return n;
    }

    // 对于其他情况,调用 unpack_scalar 处理单个索引
    return unpack_scalar(index, result, result_n);
}

/**
 * Prepare an npy_index_object from the python slicing object.
 *
 * This function handles all index preparations with the exception
 * of field access. It fills the array of index_info structs correctly.
 * It already handles the boolean array special case for fancy indexing,
 * i.e. if the index type is boolean, it is exactly one matching boolean
 * array. If the index type is fancy, the boolean array is already
 * converted to integer arrays. There is (as before) no checking of the
 * boolean dimension.
 *
 * Checks everything but the bounds.
 *
 * @param the array being indexed
 * @param the index object
 * @param index info struct being filled (size of NPY_MAXDIMS * 2 + 1)
 * @param number of indices found
 * @param dimension of the indexing result
 * @param dimension of the fancy/advanced indices part
 * @param whether to allow the boolean special case
 *
 * @returns the index_type or -1 on failure and fills the number of indices.
 */
NPY_NO_EXPORT int
/*
 * 准备索引函数,根据给定的索引对象和数组信息,解析并准备索引信息
 */
prepare_index(PyArrayObject *self, PyObject *index,
              npy_index_info *indices,
              int *num, int *ndim, int *out_fancy_ndim, int allow_boolean)
{
    int new_ndim, fancy_ndim, used_ndim, index_ndim;
    int curr_idx, get_idx;

    int i;
    npy_intp n;

    PyObject *obj = NULL;
    PyArrayObject *arr;

    int index_type = 0;
    int ellipsis_pos = -1;

    /*
     * 选择解包 `2*NPY_MAXDIMS` 项的历史原因。
     * 最长的“合理”索引,生成的结果维度最多为 32,
     * 是 `(0,)*ncu.MAXDIMS + (None,)*ncu.MAXDIMS`。
     * 更长的索引可能存在,但并不常见。
     */
    PyObject *raw_indices[NPY_MAXDIMS*2];

    // 解包索引对象,填充 raw_indices 数组,返回索引的维度
    index_ndim = unpack_indices(index, raw_indices, NPY_MAXDIMS*2);
    if (index_ndim == -1) {
        return -1;
    }

    /*
     * 将所有索引解析到 indices 数组中的 index_info 结构体中
     */
    used_ndim = 0;
    new_ndim = 0;
    fancy_ndim = 0;
    get_idx = 0;
    curr_idx = 0;

    /*
     * 比较索引的维度和实际的维度。这是为了找到省略号值或在必要时添加省略号。
     */
    if (used_ndim < PyArray_NDIM(self)) {
        if (index_type & HAS_ELLIPSIS) {
            // 设置省略号的值并更新维度计数
            indices[ellipsis_pos].value = PyArray_NDIM(self) - used_ndim;
            used_ndim = PyArray_NDIM(self);
            new_ndim += indices[ellipsis_pos].value;
        }
        else {
            /*
             * 尚未有省略号,但索引不完整,因此在末尾添加省略号。
             */
            index_type |= HAS_ELLIPSIS;
            indices[curr_idx].object = NULL;
            indices[curr_idx].type = HAS_ELLIPSIS;
            indices[curr_idx].value = PyArray_NDIM(self) - used_ndim;
            ellipsis_pos = curr_idx;

            used_ndim = PyArray_NDIM(self);
            new_ndim += indices[curr_idx].value;
            curr_idx += 1;
        }
    }
    else if (used_ndim > PyArray_NDIM(self)) {
        // 索引的维度超过数组的维度,抛出 IndexError 异常
        PyErr_Format(PyExc_IndexError,
                     "too many indices for array: "
                     "array is %d-dimensional, but %d were indexed",
                     PyArray_NDIM(self),
                     used_ndim);
        goto failed_building_indices;
    }
    else if (index_ndim == 0) {
        /*
         * 0 维度索引到 0 维度数组,即 array[()]。
         * 我们将其视为整数索引,返回标量值。
         * 这是有道理的,因为 array[...] 返回数组,而 array[()] 返回标量。
         */
        used_ndim = 0;
        index_type = HAS_INTEGER;
    }

    /* HAS_SCALAR_ARRAY 需要清理 index_type */
    if (index_type & HAS_SCALAR_ARRAY) {
        /* 如果索引类型包含标志 HAS_SCALAR_ARRAY */
        /* 清除这个信息,因为后续处理中不需要它,会增加复杂度 */
        if (index_type & HAS_FANCY) {
            index_type -= HAS_SCALAR_ARRAY;
        }
        /* 对于完整的整数索引,标量数组被视为整数索引的一部分 */
        else if (index_type == (HAS_INTEGER | HAS_SCALAR_ARRAY)) {
            index_type -= HAS_SCALAR_ARRAY;
        }
    }

    /*
     * 到这一步,索引已经全部正确设置,没有进行边界检查,
     * 新的数组可能仍然具有比可能的维度更多的维度,
     * 并且布尔索引数组的形状可能不正确。
     *
     * 现在检查这些,这样我们以后就不必担心了。
     * 这可能发生在使用 fancy indexing 或者 newaxis 时。
     * 这意味着在维度过多时,广播错误的情况会更少发生。
     */
    if (index_type & (HAS_NEWAXIS | HAS_FANCY)) {
        if (new_ndim + fancy_ndim > NPY_MAXDIMS) {
            /* 如果新的数组维度和 fancy 索引维度总和超过了 NPY_MAXDIMS */
            /* 报错,指数的数量必须在 [0, NPY_MAXDIMS] 范围内,索引结果会有 %d 维度 */
            PyErr_Format(PyExc_IndexError,
                         "number of dimensions must be within [0, %d], "
                         "indexing result would have %d",
                         NPY_MAXDIMS, (new_ndim + fancy_ndim));
            goto failed_building_indices;
        }

        /*
         * 如果我们有一个 fancy 索引,可能有一个布尔数组索引。
         * 现在检查它的形状是否正确,因为我们可以找出它作用的轴。
         */
        used_ndim = 0;
        for (i = 0; i < curr_idx; i++) {
            if ((indices[i].type == HAS_FANCY) && indices[i].value > 0) {
                if (indices[i].value != PyArray_DIM(self, used_ndim)) {
                    char err_msg[174];

                    PyOS_snprintf(err_msg, sizeof(err_msg),
                        "boolean index did not match indexed array along "
                        "axis %d; size of axis is %" NPY_INTP_FMT
                        " but size of corresponding boolean axis is %" NPY_INTP_FMT,
                        used_ndim, PyArray_DIM(self, used_ndim),
                        indices[i].value);
                    PyErr_SetString(PyExc_IndexError, err_msg);
                    goto failed_building_indices;
                }
            }

            if (indices[i].type == HAS_ELLIPSIS) {
                used_ndim += indices[i].value;
            }
            else if ((indices[i].type == HAS_NEWAXIS) ||
                     (indices[i].type == HAS_0D_BOOL)) {
                used_ndim += 0;
            }
            else {
                used_ndim += 1;
            }
        }
    }

    /* 将 curr_idx 赋值给 num */
    *num = curr_idx;
    /* 将 new_ndim + fancy_ndim 赋值给 ndim */
    *ndim = new_ndim + fancy_ndim;
    /* 将 fancy_ndim 赋值给 out_fancy_ndim */
    *out_fancy_ndim = fancy_ndim;

    /* 减少 raw_indices 的引用计数,释放内存 */
    multi_DECREF(raw_indices, index_ndim);

    /* 返回索引类型 */
    return index_type;

  failed_building_indices:
    /* 处理构建索引失败的情况 */
    for (i=0; i < curr_idx; i++) {
        Py_XDECREF(indices[i].object);
    }
    /* 减少 raw_indices 的引用计数,释放内存 */
    multi_DECREF(raw_indices, index_ndim);
    /* 返回错误状态 */
    return -1;
/**
 * Check if self has memory overlap with one of the index arrays, or with extra_op.
 *
 * @returns 1 if memory overlap found, 0 if not.
 */
NPY_NO_EXPORT int
index_has_memory_overlap(PyArrayObject *self,
                         int index_type, npy_index_info *indices, int num,
                         PyObject *extra_op)
{
    int i;

    // 如果索引类型包含花式索引或布尔索引
    if (index_type & (HAS_FANCY | HAS_BOOL)) {
        // 遍历索引数组
        for (i = 0; i < num; ++i) {
            // 如果索引对象存在且为数组,并且与 self 存在内存重叠
            if (indices[i].object != NULL &&
                    PyArray_Check(indices[i].object) &&
                    solve_may_share_memory(self,
                                           (PyArrayObject *)indices[i].object,
                                           1) != 0) {
                return 1;
            }
        }
    }

    // 如果存在额外操作对象,并且额外操作对象是数组,并且与 self 存在内存重叠
    if (extra_op != NULL && PyArray_Check(extra_op) &&
            solve_may_share_memory(self, (PyArrayObject *)extra_op, 1) != 0) {
        return 1;
    }

    // 没有发现内存重叠
    return 0;
}


/**
 * Get pointer for an integer index.
 *
 * For a purely integer index, set ptr to the memory address.
 * Returns 0 on success, -1 on failure.
 * The caller must ensure that the index is a full integer
 * one.
 *
 * @param Array being indexed
 * @param result pointer
 * @param parsed index information
 * @param number of indices
 *
 * @return 0 on success -1 on failure
 */
static int
get_item_pointer(PyArrayObject *self, char **ptr,
                    npy_index_info *indices, int index_num) {
    int i;
    // 设置指针为数组的起始地址
    *ptr = PyArray_BYTES(self);
    // 遍历所有索引
    for (i=0; i < index_num; i++) {
        // 检查并调整索引值,确保在有效范围内
        if ((check_and_adjust_index(&(indices[i].value),
                               PyArray_DIMS(self)[i], i, NULL)) < 0) {
            return -1;
        }
        // 计算指针偏移量
        *ptr += PyArray_STRIDE(self, i) * indices[i].value;
    }
    return 0;
}


/**
 * Get view into an array using all non-array indices.
 *
 * For any index, get a view of the subspace into the original
 * array. If there are no fancy indices, this is the result of
 * the indexing operation.
 * Ensure_array allows to fetch a safe subspace view for advanced
 * indexing.
 *
 * @param Array being indexed
 * @param resulting array (new reference)
 * @param parsed index information
 * @param number of indices
 * @param Whether result should inherit the type from self
 *
 * @return 0 on success -1 on failure
 */
static int
get_view_from_index(PyArrayObject *self, PyArrayObject **view,
                    npy_index_info *indices, int index_num, int ensure_array) {
    npy_intp new_strides[NPY_MAXDIMS];
    npy_intp new_shape[NPY_MAXDIMS];
    int i, j;
    int new_dim = 0;
    int orig_dim = 0;
    // 获取数组的起始地址
    char *data_ptr = PyArray_BYTES(self);

    /* for slice parsing */
    npy_intp start, stop, step, n_steps;

    // 更多功能索引解析...
    for (i=0; i < index_num; i++) {
        // 根据索引类型进行处理
        switch (indices[i].type) {
            case HAS_INTEGER:
                // 如果索引类型是整数,检查并调整索引值
                if ((check_and_adjust_index(&indices[i].value,
                                PyArray_DIMS(self)[orig_dim], orig_dim,
                                NULL)) < 0) {
                    return -1;
                }
                // 根据数组在原始维度上的步长和调整后的索引值更新数据指针位置
                data_ptr += PyArray_STRIDE(self, orig_dim) * indices[i].value;

                // 增加新维度的计数,原始维度加一
                new_dim += 0;
                orig_dim += 1;
                break;
            case HAS_ELLIPSIS:
                // 如果索引类型是省略号,根据省略号值设置新的步长和形状
                for (j=0; j < indices[i].value; j++) {
                    new_strides[new_dim] = PyArray_STRIDE(self, orig_dim);
                    new_shape[new_dim] = PyArray_DIMS(self)[orig_dim];
                    new_dim += 1;
                    orig_dim += 1;
                }
                break;
            case HAS_SLICE:
                // 如果索引类型是切片,获取切片的起始、停止、步长等参数
                if (PySlice_GetIndicesEx(indices[i].object,
                                         PyArray_DIMS(self)[orig_dim],
                                         &start, &stop, &step, &n_steps) < 0) {
                    return -1;
                }
                // 处理步长非正数的情况
                if (n_steps <= 0) {
                    /* TODO: Always points to start then, could change that */
                    n_steps = 0;
                    step = 1;
                    start = 0;
                }

                // 根据切片的起始位置更新数据指针位置
                data_ptr += PyArray_STRIDE(self, orig_dim) * start;
                // 设置新维度的步长和形状
                new_strides[new_dim] = PyArray_STRIDE(self, orig_dim) * step;
                new_shape[new_dim] = n_steps;
                new_dim += 1;
                orig_dim += 1;
                break;
            case HAS_NEWAXIS:
                // 如果索引类型是新轴,设置新轴的步长为0,形状为1
                new_strides[new_dim] = 0;
                new_shape[new_dim] = 1;
                new_dim += 1;
                break;
            /* Fancy and 0-d boolean indices are ignored here */
            case HAS_0D_BOOL:
                // 忽略特殊情况:精确索引和0维布尔索引
                break;
            default:
                // 默认情况下,增加新维度计数,原始维度加一
                new_dim += 0;
                orig_dim += 1;
                break;
        }
    }

    /* 创建新视图并设置基础数组 */
    // 增加基础数组的引用计数
    Py_INCREF(PyArray_DESCR(self));
    // 使用给定的描述符和参数创建新的数组视图
    *view = (PyArrayObject *)PyArray_NewFromDescr_int(
            ensure_array ? &PyArray_Type : Py_TYPE(self),
            PyArray_DESCR(self),
            new_dim, new_shape, new_strides, data_ptr,
            PyArray_FLAGS(self),
            ensure_array ? NULL : (PyObject *)self,
            (PyObject *)self, _NPY_ARRAY_ENSURE_DTYPE_IDENTITY);
    // 检查视图创建是否成功
    if (*view == NULL) {
        return -1;
    }

    // 返回成功
    return 0;
}

/*
 * Implements boolean indexing. This produces a one-dimensional
 * array which picks out all of the elements of 'self' for which
 * the corresponding element of 'op' is True.
 *
 * This operation is somewhat unfortunate, because to produce
 * a one-dimensional output array, it has to choose a particular
 * iteration order, in the case of NumPy that is always C order even
 * though this function allows different choices.
 */
NPY_NO_EXPORT PyArrayObject *
array_boolean_subscript(PyArrayObject *self,
                        PyArrayObject *bmask, NPY_ORDER order)
{
    npy_intp size, itemsize;
    char *ret_data;
    PyArray_Descr *dtype;
    PyArray_Descr *ret_dtype;
    PyArrayObject *ret;

    size = count_boolean_trues(PyArray_NDIM(bmask), PyArray_DATA(bmask),
                                PyArray_DIMS(bmask), PyArray_STRIDES(bmask));

    /* Allocate the output of the boolean indexing */
    dtype = PyArray_DESCR(self);
    Py_INCREF(dtype);
    ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, dtype, 1, &size,
                                NULL, NULL, 0, NULL);
    if (ret == NULL) {
        return NULL;
    }
    /* not same as *dtype* if the DType class replaces dtypes */
    ret_dtype = PyArray_DESCR(ret);

    itemsize = dtype->elsize;
    ret_data = PyArray_DATA(ret);

    /* Create an iterator for the data */
    }

    if (!PyArray_CheckExact(self)) {
        PyArrayObject *tmp = ret;

        Py_INCREF(ret_dtype);
        ret = (PyArrayObject *)PyArray_NewFromDescrAndBase(
                Py_TYPE(self), ret_dtype,
                1, &size, PyArray_STRIDES(ret), PyArray_BYTES(ret),
                PyArray_FLAGS(self), (PyObject *)self, (PyObject *)tmp);

        Py_DECREF(tmp);
        if (ret == NULL) {
            return NULL;
        }
    }

    return ret;
}

/*
 * Implements boolean indexing assignment. This takes the one-dimensional
 * array 'v' and assigns its values to all of the elements of 'self' for which
 * the corresponding element of 'op' is True.
 *
 * This operation is somewhat unfortunate, because to match up with
 * a one-dimensional output array, it has to choose a particular
 * iteration order, in the case of NumPy that is always C order even
 * though this function allows different choices.
 *
 * Returns 0 on success, -1 on failure.
 */
NPY_NO_EXPORT int
array_assign_boolean_subscript(PyArrayObject *self,
                    PyArrayObject *bmask, PyArrayObject *v, NPY_ORDER order)
{
    npy_intp size, v_stride;
    char *v_data;
    npy_intp bmask_size;

    if (PyArray_DESCR(bmask)->type_num != NPY_BOOL) {
        PyErr_SetString(PyExc_TypeError,
                "NumPy boolean array indexing assignment "
                "requires a boolean index");
        return -1;
    }
}
    // 检查输入数组 v 是否为多维数组(大于1维)
    if (PyArray_NDIM(v) > 1) {
        // 报错并返回 -1,要求 NumPy 布尔数组索引赋值需要输入为 01 维
        PyErr_Format(PyExc_TypeError,
                "NumPy boolean array indexing assignment "
                "requires a 0 or 1-dimensional input, input "
                "has %d dimensions", PyArray_NDIM(v));
        return -1;
    }

    // 检查布尔掩码数组 bmask 的维度是否与被索引数组 self 的维度相同
    if (PyArray_NDIM(bmask) != PyArray_NDIM(self)) {
        // 报错并返回 -1,要求布尔掩码索引数组必须与被索引数组 self 的维度相同
        PyErr_SetString(PyExc_ValueError,
                "The boolean mask assignment indexing array "
                "must have the same number of dimensions as "
                "the array being indexed");
        return -1;
    }

    // 计算布尔掩码中 True 的数量
    size = count_boolean_trues(PyArray_NDIM(bmask), PyArray_DATA(bmask),
                                PyArray_DIMS(bmask), PyArray_STRIDES(bmask));
    /* 用于调整广播 'bmask''self' 的修正因子 */
    bmask_size = PyArray_SIZE(bmask);
    if (bmask_size > 0) {
        size *= PyArray_SIZE(self) / bmask_size;
    }

    // 调整用于 0 维和广播情况的步长
    if (PyArray_NDIM(v) > 0 && PyArray_DIMS(v)[0] != 1) {
        // 如果 v 是一维数组且长度与 size 不一致,则报错
        if (size != PyArray_DIMS(v)[0]) {
            PyErr_Format(PyExc_ValueError,
                    "NumPy boolean array indexing assignment "
                    "cannot assign %" NPY_INTP_FMT " input values to "
                    "the %" NPY_INTP_FMT " output values where the mask is true",
                    PyArray_DIMS(v)[0], size);
            return -1;
        }
        // 获取 v 的步长
        v_stride = PyArray_STRIDES(v)[0];
    }
    else {
        // 对于 0 维数组,步长设为 0
        v_stride = 0;
    }

    // 获取数组 v 的数据指针
    v_data = PyArray_DATA(v);

    /* 为数据创建迭代器 */
    // 初始化结果变量为 0
    int res = 0;
    // 返回结果
    return res;
}
/*
 * C-level integer indexing always returning an array and never a scalar.
 * Works also for subclasses, but it will not be called on one from the
 * Python API.
 *
 * This function does not accept negative indices because it is called by
 * PySequence_GetItem (through array_item) and that converts them to
 * positive indices.
 */
NPY_NO_EXPORT PyObject *
array_item_asarray(PyArrayObject *self, npy_intp i)
{
    npy_index_info indices[2];  // 定义索引信息结构体数组
    PyObject *result;  // 结果对象指针

    if (PyArray_NDIM(self) == 0) {
        PyErr_SetString(PyExc_IndexError,
                        "too many indices for array");
        return NULL;  // 如果数组维度为0,抛出索引错误并返回空
    }
    if (i < 0) {
        /* This is an error, but undo PySequence_GetItem fix for message */
        i -= PyArray_DIM(self, 0);  // 如果索引为负数,将其转换为正数
    }

    indices[0].value = i;  // 设置第一个索引的值为 i
    indices[0].type = HAS_INTEGER;  // 表示第一个索引是整数类型
    indices[1].value = PyArray_NDIM(self) - 1;  // 设置第二个索引的值为数组的最后一个维度
    indices[1].type = HAS_ELLIPSIS;  // 表示第二个索引是省略号类型
    if (get_view_from_index(self, (PyArrayObject **)&result,
                            indices, 2, 0) < 0) {
        return NULL;  // 根据索引获取视图对象,失败则返回空
    }
    return result;  // 返回获取的结果对象
}


/*
 * Python C-Api level item subscription (implementation for PySequence_GetItem)
 *
 * Negative indices are not accepted because PySequence_GetItem converts
 * them to positive indices before calling this.
 */
NPY_NO_EXPORT PyObject *
array_item(PyArrayObject *self, Py_ssize_t i)
{
    if (PyArray_NDIM(self) == 1) {  // 如果数组维度为1
        char *item;  // 字符指针 item
        npy_index_info index;  // 索引信息结构体

        if (i < 0) {
            /* This is an error, but undo PySequence_GetItem fix for message */
            i -= PyArray_DIM(self, 0);  // 如果索引为负数,将其转换为正数
        }

        index.value = i;  // 设置索引值为 i
        index.type = HAS_INTEGER;  // 表示索引为整数类型
        if (get_item_pointer(self, &item, &index, 1) < 0) {
            return NULL;  // 获取数组项指针,失败则返回空
        }
        return PyArray_Scalar(item, PyArray_DESCR(self), (PyObject *)self);  // 根据数组项创建标量对象并返回
    }
    else {
        return array_item_asarray(self, i);  // 如果数组维度不为1,调用 array_item_asarray 函数处理
    }
}


/* make sure subscript always returns an array object */
NPY_NO_EXPORT PyObject *
array_subscript_asarray(PyArrayObject *self, PyObject *op)
{
    return PyArray_EnsureAnyArray(array_subscript(self, op));  // 确保使用下标访问时总是返回一个数组对象
}

/*
 * Attempts to subscript an array using a field name or list of field names.
 *
 * ret =  0, view != NULL: view points to the requested fields of arr
 * ret =  0, view == NULL: an error occurred
 * ret = -1, view == NULL: unrecognized input, this is not a field index.
 */
NPY_NO_EXPORT int
_get_field_view(PyArrayObject *arr, PyObject *ind, PyArrayObject **view)
{
    assert(PyDataType_ISLEGACY(PyArray_DESCR(arr)));  // 断言数组的数据类型是遗留类型
    *view = NULL;  // 将视图对象指针初始化为空

    /* first check for a single field name */
    /* 检查是否为 Unicode 对象 */
    if (PyUnicode_Check(ind)) {
        PyObject *tup;
        PyArray_Descr *fieldtype;
        npy_intp offset;

        /* 获取字段偏移量和数据类型 */
        tup = PyDict_GetItemWithError(PyDataType_FIELDS(PyArray_DESCR(arr)), ind);
        if (tup == NULL && PyErr_Occurred()) {
            return 0;
        }
        else if (tup == NULL){
            PyErr_Format(PyExc_ValueError, "no field of name %S", ind);
            return 0;
        }
        if (_unpack_field(tup, &fieldtype, &offset) < 0) {
            return 0;
        }

        /* 在新的偏移量和数据类型下查看数组 */
        Py_INCREF(fieldtype);
        *view = (PyArrayObject*)PyArray_NewFromDescr_int(
                Py_TYPE(arr),
                fieldtype,
                PyArray_NDIM(arr),
                PyArray_SHAPE(arr),
                PyArray_STRIDES(arr),
                PyArray_BYTES(arr) + offset,
                PyArray_FLAGS(arr),
                (PyObject *)arr, (PyObject *)arr,
                /* 仅对字符串进行子数组时不保留数据类型 */
                _NPY_ARRAY_ALLOW_EMPTY_STRING);
        if (*view == NULL) {
            return 0;
        }
        return 0;
    }

    /* 检查是否为字段名列表 */
    else if (PySequence_Check(ind) && !PyTuple_Check(ind)) {
        npy_intp seqlen, i;
        PyArray_Descr *view_dtype;

        seqlen = PySequence_Size(ind);

        /* 如果是虚假的类似序列且调用 len() 时出错则退出 */
        if (seqlen == -1) {
            PyErr_Clear();
            return -1;
        }
        /* 处理空列表作为整数索引的情况 */
        if (seqlen == 0) {
            return -1;
        }

        /* 检查所有项是否为字符串 */
        for (i = 0; i < seqlen; i++) {
            npy_bool is_string;
            PyObject *item = PySequence_GetItem(ind, i);
            if (item == NULL) {
                PyErr_Clear();
                return -1;
            }
            is_string = PyUnicode_Check(item);
            Py_DECREF(item);
            if (!is_string) {
                return -1;
            }
        }

        /* 调用 dtype 的下标操作 */
        view_dtype = arraydescr_field_subset_view(
                (_PyArray_LegacyDescr *)PyArray_DESCR(arr), ind);
        if (view_dtype == NULL) {
            return 0;
        }

        *view = (PyArrayObject*)PyArray_NewFromDescr_int(
                Py_TYPE(arr),
                view_dtype,
                PyArray_NDIM(arr),
                PyArray_SHAPE(arr),
                PyArray_STRIDES(arr),
                PyArray_DATA(arr),
                PyArray_FLAGS(arr),
                (PyObject *)arr, (PyObject *)arr,
                /* 仅对字符串进行子数组时不保留数据类型 */
                _NPY_ARRAY_ALLOW_EMPTY_STRING);

        if (*view == NULL) {
            return 0;
        }

        return 0;
    }
    /* 默认情况返回 -1 */
    return -1;
}

/*
 * General function for indexing a NumPy array with a Python object.
 */
NPY_NO_EXPORT PyObject *
array_subscript(PyArrayObject *self, PyObject *op)
{
    // 定义索引类型、索引数量以及循环变量等
    int index_type;
    int index_num;
    int i, ndim, fancy_ndim;
    // 初始化类型为 NPY_cast_info 的结构体 cast_info,并设置 func 字段为 NULL
    NPY_cast_info cast_info = {.func = NULL};

    /*
     * Index info array. We can have twice as many indices as dimensions
     * (because of None). The + 1 is to not need to check as much.
     */
    // 定义索引信息数组,数组大小为 NPY_MAXDIMS * 2 + 1,用于存储索引信息
    npy_index_info indices[NPY_MAXDIMS * 2 + 1];

    // 定义视图和结果对象,并初始化为 NULL
    PyArrayObject *view = NULL;
    PyObject *result = NULL;

    // 定义 PyArrayMapIterObject 类型指针 mit,并初始化为 NULL
    PyArrayMapIterObject * mit = NULL;

    /* return fields if op is a string index */
    // 如果 op 是字符串索引,并且数组描述符有字段信息
    if (PyDataType_HASFIELDS(PyArray_DESCR(self))) {
        // 声明视图对象 view,并调用 _get_field_view 函数
        PyArrayObject *view;
        // 调用 _get_field_view 函数尝试获取字段视图,结果存入 view
        int ret = _get_field_view(self, op, &view);
        // 如果 ret 等于 0,则成功获取视图
        if (ret == 0){
            // 如果视图为 NULL,返回 NULL
            if (view == NULL) {
                return NULL;
            }
            // 返回视图对象
            return (PyObject*)view;
        }
    }

    // 准备索引信息
    index_type = prepare_index(self, op, indices, &index_num,
                               &ndim, &fancy_ndim, 1);

    // 如果准备索引失败,返回 NULL
    if (index_type < 0) {
        return NULL;
    }

    // 如果索引类型是完全整数索引
    else if (index_type == HAS_INTEGER) {
        // 获取数组中元素的指针
        char *item;
        if (get_item_pointer(self, &item, indices, index_num) < 0) {
            // 如果获取失败,跳转到 finish 标签
            goto finish;
        }
        // 创建并返回数组标量对象
        result = (PyObject *) PyArray_Scalar(item, PyArray_DESCR(self),
                                             (PyObject *)self);
        /* Because the index is full integer, we do not need to decref */
        // 因为索引是完全整数,不需要减少引用计数
        return result;
    }

    // 如果索引类型是布尔数组索引
    else if (index_type == HAS_BOOL) {
        // 使用布尔数组索引进行数组子脚本操作,并返回结果对象
        result = (PyObject *)array_boolean_subscript(self,
                                    (PyArrayObject *)indices[0].object,
                                    NPY_CORDER);
        // 跳转到 finish 标签
        goto finish;
    }

    // 如果索引类型是单个省略号索引
    else if (index_type == HAS_ELLIPSIS) {
        /*
         * TODO: Should this be a view or not? The only reason not would be
         *       optimization (i.e. of array[...] += 1) I think.
         *       Before, it was just self for a single ellipsis.
         */
        // 创建并返回数组的视图对象
        result = PyArray_View(self, NULL, NULL);
        /* A single ellipsis, so no need to decref */
        // 单个省略号索引,不需要减少引用计数
        return result;
    }

    /*
     * View based indexing.
     * There are two cases here. First we need to create a simple view,
     * second we need to create a (possibly invalid) view for the
     * subspace to the fancy index. This procedure is identical.
     */
    # 如果索引类型包含切片、新轴、省略号或整数
    else if (index_type & (HAS_SLICE | HAS_NEWAXIS |
                           HAS_ELLIPSIS | HAS_INTEGER)) {
        # 尝试从索引中获取视图对象,若失败则跳转到结束
        if (get_view_from_index(self, &view, indices, index_num,
                                (index_type & HAS_FANCY)) < 0) {
            goto finish;
        }

        '''
         * 存在标量数组,需要强制复制以模拟花式索引。
         '''
        if (index_type & HAS_SCALAR_ARRAY) {
            result = PyArray_NewCopy(view, NPY_KEEPORDER);
            goto finish;
        }
    }

    '''
     * 如果没有花式索引,直接使用视图对象作为结果。
     '''
    # 如果没有花式索引,则结果是视图对象本身
    if (!(index_type & HAS_FANCY)) {
        result = (PyObject *)view;
        Py_INCREF(result);
        goto finish;
    }

    '''
     * 特殊情况:非常简单的一维花式索引,尽管如此常见。
     * 这不仅节省了迭代器的设置时间,而且更快(必须完全是花式索引,
     * 因为这里不支持0维布尔值)。
     '''
    if (index_type == HAS_FANCY && index_num == 1) {
        /* 如果索引类型为 HAS_FANCY 并且索引数量为 1 */

        PyArrayObject *ind = (PyArrayObject*)indices[0].object;
        /* 将索引对象转换为 PyArrayObject 类型 */

        if (PyArray_TRIVIALLY_ITERABLE(ind) &&
                /* 检查索引是否足够简单 */
                PyArray_ITEMSIZE(ind) == sizeof(npy_intp) &&
                PyArray_DESCR(ind)->kind == 'i' &&
                IsUintAligned(ind) &&
                PyDataType_ISNOTSWAPPED(PyArray_DESCR(ind))) {
            /* 检查类型是否等同于 INTP */
            
            Py_INCREF(PyArray_DESCR(self));
            /* 增加对数组描述符的引用计数 */

            result = PyArray_NewFromDescr(&PyArray_Type,
                                          PyArray_DESCR(self),
                                          PyArray_NDIM(ind),
                                          PyArray_SHAPE(ind),
                                          NULL, NULL,
                                          /* 与索引顺序相同 */
                                          PyArray_ISFORTRAN(ind) ?
                                              NPY_ARRAY_F_CONTIGUOUS : 0,
                                          NULL);
            /* 使用给定的描述符和形状创建新的数组对象 */

            if (result == NULL) {
                goto finish;
            }

            NPY_ARRAYMETHOD_FLAGS transfer_flags;
            npy_intp itemsize = PyArray_ITEMSIZE(self);
            /* 获取数组元素的大小 */
            int is_aligned = IsUintAligned(self);
            /* 检查数组是否按无符号整数对齐 */

            if (PyArray_GetDTypeTransferFunction(is_aligned,
                    itemsize, itemsize,
                    PyArray_DESCR(self), PyArray_DESCR((PyArrayObject *)result),
                    0, &cast_info, &transfer_flags) != NPY_SUCCEED) {
                goto finish;
            }

            if (mapiter_trivial_get(
                    self, ind, (PyArrayObject *)result, is_aligned, &cast_info) < 0) {
                /* 调用 mapiter_trivial_get 函数获取数据 */
                Py_DECREF(result);
                result = NULL;
                goto finish;
            }

            goto wrap_out_array;
            /* 跳转到 wrap_out_array 标签处 */
        }
    }

    /* 必须使用花式索引。视图是子空间。 */
    mit = (PyArrayMapIterObject *)PyArray_MapIterNew(indices, index_num,
                                                     index_type,
                                                     ndim, fancy_ndim,
                                                     self, view, 0,
                                                     NPY_ITER_READONLY,
                                                     NPY_ITER_WRITEONLY,
                                                     NULL, PyArray_DESCR(self));
    /* 创建数组映射迭代器对象 */

    if (mit == NULL) {
        goto finish;
    }
    if (mit->num_fancy > 1 || mit->size == 0) {
        /*
         * 如果 num_fancy 大于 1 或者 size 等于 0,
         * 则需要进行内部循环检查索引;否则,
         * 在广播发生时先进行索引检查,因为这样速度更快,
         * 而且大多数情况下没有太大的开销。
         * 然而,对于 size == 0 的情况,内部循环优化会跳过索引检查。
         */
        if (PyArray_MapIterCheckIndices(mit) < 0) {
            goto finish;
        }
    }

    /* 重置外部迭代器 */
    if (NpyIter_Reset(mit->outer, NULL) < 0) {
        goto finish;
    }

    /*
     * 对齐信息(由于我们使用缓冲区,不需要进行交换),
     * 还可以检查 extra_op 是否已经缓冲,但这通常不重要。
     */
    int is_aligned = IsUintAligned(self) && IsUintAligned(mit->extra_op);
    /*
     * 注意:获取数据类型转换函数时实际上不会执行类型转换,
     *       因此我们目前不必进行完整的检查(例如浮点数错误)(不像赋值操作那样)。
     */
    int meth_flags = NpyIter_GetTransferFlags(mit->outer);
    if (mit->extra_op_iter) {
        int extra_op_flags = NpyIter_GetTransferFlags(mit->extra_op_iter);
        meth_flags = PyArrayMethod_COMBINED_FLAGS(meth_flags, extra_op_flags);
    }

    if (mit->subspace_iter != NULL) {
        int extra_op_flags = NpyIter_GetTransferFlags(mit->subspace_iter);
        meth_flags = PyArrayMethod_COMBINED_FLAGS(meth_flags, extra_op_flags);

        NPY_ARRAYMETHOD_FLAGS transfer_flags;
        npy_intp fixed_strides[2];
        /*
         * 获取 dtype 转换函数,由于没有缓冲区,这是安全的。
         */
        NpyIter_GetInnerFixedStrideArray(mit->subspace_iter, fixed_strides);

        if (PyArray_GetDTypeTransferFunction(is_aligned,
                fixed_strides[0], fixed_strides[1],
                PyArray_DESCR(self), PyArray_DESCR(mit->extra_op),
                0, &cast_info, &transfer_flags) != NPY_SUCCEED) {
            goto finish;
        }
        meth_flags = PyArrayMethod_COMBINED_FLAGS(meth_flags, transfer_flags);
    }
    else {
        /* 可能需要一个通用的复制函数(仅用于引用和奇怪的大小) */
        NPY_ARRAYMETHOD_FLAGS transfer_flags;
        npy_intp itemsize = PyArray_ITEMSIZE(self);

        if (PyArray_GetDTypeTransferFunction(1,
                itemsize, itemsize,
                PyArray_DESCR(self), PyArray_DESCR(self),
                0, &cast_info, &transfer_flags) != NPY_SUCCEED) {
            goto finish;
        }
        meth_flags = PyArrayMethod_COMBINED_FLAGS(meth_flags, transfer_flags);
    }

    if (mapiter_get(mit, &cast_info, meth_flags, is_aligned) < 0) {
        goto finish;
    }

    result = (PyObject *)mit->extra_op;
    Py_INCREF(result);

    if (mit->consec) {
        PyArray_MapIterSwapAxes(mit, (PyArrayObject **)&result, 1);
    }

  wrap_out_array:
    if (!PyArray_CheckExact(self)) {
        /*
         * 如果 self 不是一个确切的 PyArray 对象,需要创建一个新的数组,
         * 就好像旧数组从未存在过。
         */
        PyArrayObject *tmp_arr = (PyArrayObject *)result;

        // 增加临时数组的描述符的引用计数
        Py_INCREF(PyArray_DESCR(tmp_arr));

        // 使用临时数组的信息创建一个新的 PyArray 对象
        result = PyArray_NewFromDescrAndBase(
                Py_TYPE(self),
                PyArray_DESCR(tmp_arr),
                PyArray_NDIM(tmp_arr),
                PyArray_SHAPE(tmp_arr),
                PyArray_STRIDES(tmp_arr),
                PyArray_BYTES(tmp_arr),
                PyArray_FLAGS(tmp_arr),
                (PyObject *)self, (PyObject *)tmp_arr);
        Py_DECREF(tmp_arr);
        // 如果创建失败,跳转至结束标签 finish
        if (result == NULL) {
            goto finish;
        }
    }

  finish:
    // 释放类型转换信息结构体的内存
    NPY_cast_info_xfree(&cast_info);
    // 释放 mit 对象的引用
    Py_XDECREF(mit);
    // 释放 view 对象的引用
    Py_XDECREF(view);
    /* 清理索引数组中的对象引用 */
    for (i=0; i < index_num; i++) {
        Py_XDECREF(indices[i].object);
    }
    // 返回 result 对象
    return result;
/*
 * Python C-Api level item assignment (implementation for PySequence_SetItem)
 *
 * Negative indices are not accepted because PySequence_SetItem converts
 * them to positive indices before calling this.
 */
NPY_NO_EXPORT int
array_assign_item(PyArrayObject *self, Py_ssize_t i, PyObject *op)
{
    npy_index_info indices[2];  // 定义索引信息结构体数组,用于存储索引信息

    if (op == NULL) {  // 如果操作对象为空指针
        PyErr_SetString(PyExc_ValueError,
                        "cannot delete array elements");  // 设置错误消息:无法删除数组元素
        return -1;  // 返回错误代码
    }
    if (PyArray_FailUnlessWriteable(self, "assignment destination") < 0) {
        return -1;  // 如果数组不可写,则返回错误代码
    }
    if (PyArray_NDIM(self) == 0) {  // 如果数组维度为0
        PyErr_SetString(PyExc_IndexError,
                        "too many indices for array");  // 设置错误消息:数组索引过多
        return -1;  // 返回错误代码
    }

    if (i < 0) {  // 如果索引值为负数
        /* This is an error, but undo PySequence_SetItem fix for message */
        i -= PyArray_DIM(self, 0);  // 对负数索引进行修正
    }

    indices[0].value = i;  // 设置第一个索引值
    indices[0].type = HAS_INTEGER;  // 设置索引类型为整数索引
    if (PyArray_NDIM(self) == 1) {  // 如果数组维度为1
        char *item;
        if (get_item_pointer(self, &item, indices, 1) < 0) {
            return -1;  // 获取数组元素指针失败,则返回错误代码
        }
        if (PyArray_Pack(PyArray_DESCR(self), item, op) < 0) {
            return -1;  // 将 Python 对象打包为数组元素失败,则返回错误代码
        }
    }
    else {  // 如果数组维度大于1
        PyArrayObject *view;

        indices[1].value = PyArray_NDIM(self) - 1;  // 设置第二个索引值为最后一个维度索引
        indices[1].type = HAS_ELLIPSIS;  // 设置第二个索引类型为省略号索引
        if (get_view_from_index(self, &view, indices, 2, 0) < 0) {
            return -1;  // 从索引获取视图对象失败,则返回错误代码
        }
        if (PyArray_CopyObject(view, op) < 0) {
            Py_DECREF(view);
            return -1;  // 复制对象到视图对象失败,则返回错误代码
        }
        Py_DECREF(view);
    }
    return 0;  // 返回成功代码
}
    /* Full integer index */
    // 如果索引类型为整数数组
    if (index_type == HAS_INTEGER) {
        char *item;
        // 获取索引的指针
        if (get_item_pointer(self, &item, indices, index_num) < 0) {
            return -1;
        }
        // 将 item 打包到 self 中
        if (PyArray_Pack(PyArray_DESCR(self), item, op) < 0) {
            return -1;
        }
        /* integers do not store objects in indices */
        // 整数索引不存储对象
        return 0;
    }

    /* Single boolean array */
    // 如果索引类型为布尔数组
    if (index_type == HAS_BOOL) {
        if (!PyArray_Check(op)) {
            // 如果 op 不是数组,则创建一个新的数组 tmp_arr
            Py_INCREF(PyArray_DESCR(self));
            tmp_arr = (PyArrayObject *)PyArray_FromAny(op,
                                                   PyArray_DESCR(self), 0, 0,
                                                   NPY_ARRAY_FORCECAST, NULL);
            if (tmp_arr == NULL) {
                goto fail;
            }
        }
        else {
            // 如果 op 已经是数组,则直接增加引用计数
            Py_INCREF(op);
            tmp_arr = (PyArrayObject *)op;
        }

        // 使用布尔子脚本进行数组分配
        if (array_assign_boolean_subscript(self,
                                           (PyArrayObject *)indices[0].object,
                                           tmp_arr, NPY_CORDER) < 0) {
            goto fail;
        }
        // 成功时跳转到 success 标签
        goto success;
    }


    /*
     * Single ellipsis index, no need to create a new view.
     * Note that here, we do *not* go through self.__getitem__ for subclasses
     * (defchar array failed then, due to uninitialized values...)
     */
    // 如果索引类型为省略号
    else if (index_type == HAS_ELLIPSIS) {
        if ((PyObject *)self == op) {
            /*
             * CopyObject does not handle this case gracefully and
             * there is nothing to do. Removing the special case
             * will cause segfaults, though it is unclear what exactly
             * happens.
             */
            // 如果 self 和 op 相同,则无需处理,直接返回
            return 0;
        }
        /* we can just use self, but incref for error handling */
        // 我们可以直接使用 self,但需要增加引用计数以处理错误
        Py_INCREF((PyObject *)self);
        view = self;
    }

    /*
     * WARNING: There is a huge special case here. If this is not a
     *          base class array, we have to get the view through its
     *          very own index machinery.
     *          Many subclasses should probably call __setitem__
     *          with a base class ndarray view to avoid this.
     */
    // 如果索引类型既不是花式索引也不是标量数组,并且 self 不是精确的数组类型
    else if (!(index_type & (HAS_FANCY | HAS_SCALAR_ARRAY))
                && !PyArray_CheckExact(self)) {
        // 通过索引获取视图
        view = (PyArrayObject *)PyObject_GetItem((PyObject *)self, ind);
        if (view == NULL) {
            goto fail;
        }
        // 确保返回的是一个数组
        if (!PyArray_Check(view)) {
            PyErr_SetString(PyExc_RuntimeError,
                            "Getitem not returning array");
            goto fail;
        }
    }

    /*
     * View based indexing.
     * There are two cases here. First we need to create a simple view,
     * second we need to create a (possibly invalid) view for the
     * subspace to the fancy index. This procedure is identical.
     */
    // 基于视图的索引操作
    # 如果索引类型中包含切片、新轴、省略或整数
    else if (index_type & (HAS_SLICE | HAS_NEWAXIS |
                           HAS_ELLIPSIS | HAS_INTEGER)) {
        # 如果需要从索引中获取视图,并且不是花式索引,则执行以下逻辑
        if (get_view_from_index(self, &view, indices, index_num,
                                (index_type & HAS_FANCY)) < 0) {
            # 获取视图失败,则跳转到失败处
            goto fail;
        }
    }
    else {
        # 否则,将视图设为NULL
        view = NULL;
    }

    /* 如果没有花式索引,直接将视图拷贝给操作数 */
    if (!(index_type & HAS_FANCY)) {
        # 如果能够成功拷贝视图给操作数
        if (PyArray_CopyObject(view, op) < 0) {
            # 拷贝失败,则跳转到失败处
            goto fail;
        }
        # 跳转到成功处
        goto success;
    }

    # 如果操作数不是一个数组
    if (!PyArray_Check(op)) {
        /*
         * 如果数组是对象数组,并且操作数是一个序列,
         * 尽管普通赋值可行,但转换值到数组可能不合法。
         * 因此,分配一个正确大小的临时数组,并使用普通赋值处理这种情况。
         */
        if (PyDataType_REFCHK(descr) && PySequence_Check(op)) {
            # 临时数组设为NULL
            tmp_arr = NULL;
        }
        else {
            /* 没有可能使用花式索引,因此只需创建一个数组 */
            # 增加描述符的引用计数
            Py_INCREF(descr);
            # 从操作数创建一个数组,强制转换类型
            tmp_arr = (PyArrayObject *)PyArray_FromAny(op, descr, 0, 0,
                                                    NPY_ARRAY_FORCECAST, NULL);
            # 如果创建临时数组失败,则跳转到失败处
            if (tmp_arr == NULL) {
                goto fail;
            }
        }
    }
    else {
        # 增加操作数的引用计数
        Py_INCREF(op);
        # 将操作数强制转换为数组
        tmp_arr = (PyArrayObject *)op;
    }

    /*
     * 特殊情况处理非常简单的一维花式索引,这种情况相当常见。
     * 这不仅节省了迭代器的设置时间,而且速度更快(必须完全是花式的,
     * 因为这里不支持0维布尔值)
     */
    if (index_type == HAS_FANCY &&
            index_num == 1 && tmp_arr) {
        /* 当索引类型为HAS_FANCY且索引数量为1,并且tmp_arr不为空时进入条件判断 */

        PyArrayObject *ind = (PyArrayObject*)indices[0].object;
        /* 将索引数组转换为PyArrayObject类型 */

        /* 检查类型是否等效 */
        if (PyArray_EquivTypes(PyArray_DESCR(self),
                                   PyArray_DESCR(tmp_arr)) &&
                /*
                 * 类型要么等效,要么值必须是标量
                 */
                (PyArray_EQUIVALENTLY_ITERABLE(ind, tmp_arr,
                                               PyArray_TRIVIALLY_ITERABLE_OP_READ,
                                               PyArray_TRIVIALLY_ITERABLE_OP_READ) ||
                 (PyArray_NDIM(tmp_arr) == 0 &&
                        PyArray_TRIVIALLY_ITERABLE(ind))) &&
                /* 检查类型是否等效于INTP */
                PyArray_ITEMSIZE(ind) == sizeof(npy_intp) &&
                PyArray_DESCR(ind)->kind == 'i' &&
                IsUintAligned(ind) &&
                PyDataType_ISNOTSWAPPED(PyArray_DESCR(ind))) {

            NPY_ARRAYMETHOD_FLAGS transfer_flags;
            npy_intp itemsize = PyArray_ITEMSIZE(self);
            int is_aligned = IsUintAligned(self) && IsUintAligned(tmp_arr);

            if (PyArray_GetDTypeTransferFunction(is_aligned,
                    itemsize, itemsize,
                    PyArray_DESCR(self), PyArray_DESCR(self),
                    0, &cast_info, &transfer_flags) != NPY_SUCCEED) {
                goto fail;
            }

            /* trivial_set函数检查索引,然后进行设置 */
            if (mapiter_trivial_set(
                    self, ind, tmp_arr, is_aligned, &cast_info) < 0) {
                goto fail;
            }
            goto success;
        }
    }

    /*
     * 注意:如果tmp_arr尚未分配,则应由mit处理分配。
     *       NPY_ITER_READWRITE 对于自动分配是必要的。
     *       Readwrite 模式不允许正确地进行广播,但这样的操作数总是具有完整的大小。
     */
    mit = (PyArrayMapIterObject *)PyArray_MapIterNew(indices,
                                             index_num, index_type,
                                             ndim, fancy_ndim, self,
                                             view, 0,
                                             NPY_ITER_WRITEONLY,
                                             ((tmp_arr == NULL) ?
                                                  NPY_ITER_READWRITE :
                                                  NPY_ITER_READONLY),
                                             tmp_arr, descr);

    if (mit == NULL) {
        goto fail;
    }
    if (tmp_arr == NULL) {
        /* 如果 tmp_arr 为空指针,则需要填充额外的操作,首先需要交换 */
        tmp_arr = mit->extra_op;
        // 增加 tmp_arr 的引用计数,确保其不被释放
        Py_INCREF(tmp_arr);
        // 如果 mit->consec 为真,调用 PyArray_MapIterSwapAxes 函数交换轴
        if (mit->consec) {
            PyArray_MapIterSwapAxes(mit, &tmp_arr, 1);
            // 如果交换后 tmp_arr 为空,跳转到 fail 标签处处理错误
            if (tmp_arr == NULL) {
                goto fail;
            }
        }
        // 将 tmp_arr 的内容复制到 op 中
        if (PyArray_CopyObject(tmp_arr, op) < 0) {
             goto fail;
        }
    }

    // 检查 MapIter 对象的索引是否有效
    if (PyArray_MapIterCheckIndices(mit) < 0) {
        goto fail;
    }

    /*
     * 对齐信息(由于我们使用缓冲区,不需要交换),可以检查 extra_op 是否已缓冲,
     * 但这通常很少有影响。
     */
    int is_aligned = IsUintAligned(self) && IsUintAligned(mit->extra_op);
    // 获取迭代器的传输标志
    int meth_flags = NpyIter_GetTransferFlags(mit->outer);

    // 如果存在额外操作的迭代器
    if (mit->extra_op_iter) {
        int extra_op_flags = NpyIter_GetTransferFlags(mit->extra_op_iter);
        // 合并方法标志
        meth_flags = PyArrayMethod_COMBINED_FLAGS(meth_flags, extra_op_flags);
    }

    // 如果存在子空间迭代器
    if (mit->subspace_iter != NULL) {
        int extra_op_flags = NpyIter_GetTransferFlags(mit->subspace_iter);
        // 合并方法标志
        meth_flags = PyArrayMethod_COMBINED_FLAGS(meth_flags, extra_op_flags);

        NPY_ARRAYMETHOD_FLAGS transfer_flags;
        npy_intp fixed_strides[2];

        /*
         * 获取 dtype 传输函数,由于没有缓冲区,这是安全的。
         */
        NpyIter_GetInnerFixedStrideArray(mit->subspace_iter, fixed_strides);

        // 获取数据类型的传输函数,设置转换标志
        if (PyArray_GetDTypeTransferFunction(is_aligned,
                fixed_strides[1], fixed_strides[0],
                PyArray_DESCR(mit->extra_op), PyArray_DESCR(self),
                0, &cast_info, &transfer_flags) != NPY_SUCCEED) {
            goto fail;
        }
        // 合并方法标志
        meth_flags = PyArrayMethod_COMBINED_FLAGS(meth_flags, transfer_flags);
    }
    else {
        /* 可能需要一个通用的复制函数(仅适用于引用和奇怪的大小) */
        NPY_ARRAYMETHOD_FLAGS transfer_flags;
        npy_intp itemsize = PyArray_ITEMSIZE(self);

        // 获取数据类型的传输函数,设置转换标志
        if (PyArray_GetDTypeTransferFunction(1,
                itemsize, itemsize,
                PyArray_DESCR(self), PyArray_DESCR(self),
                0, &cast_info, &transfer_flags) != NPY_SUCCEED) {
            goto fail;
        }
        // 合并方法标志
        meth_flags = PyArrayMethod_COMBINED_FLAGS(meth_flags, transfer_flags);
    }

    // 如果方法标志不包含 NPY_METH_NO_FLOATINGPOINT_ERRORS,则清除浮点状态
    if (!(meth_flags & NPY_METH_NO_FLOATINGPOINT_ERRORS)) {
        npy_clear_floatstatus_barrier((char *)mit);
    }

    // 现在可以重置外部迭代器(延迟 bufalloc)
    if (NpyIter_Reset(mit->outer, NULL) < 0) {
        goto fail;
    }

    /*
     * 可能需要一个类型转换检查,但显然大多数赋值操作不关心安全转换。
     */
    // 如果设置 MapIter 的函数失败,则跳转到 fail 处理错误
    if (mapiter_set(mit, &cast_info, meth_flags, is_aligned) < 0) {
        goto fail;
    }

    // 如果方法标志不包含 NPY_METH_NO_FLOATINGPOINT_ERRORS,则获取浮点错误状态
    if (!(meth_flags & NPY_METH_NO_FLOATINGPOINT_ERRORS)) {
        int fpes = npy_get_floatstatus_barrier((char *)mit);
        // 如果获取到浮点错误并且处理浮点错误失败,则跳转到 fail 处理错误
        if (fpes && PyUFunc_GiveFloatingpointErrors("cast", fpes) < 0) {
            goto fail;
        }

    // 如果 tmp_arr 为空指针,则需要填充额外的操作,首先需要交换
    if (tmp_arr == NULL) {
        tmp_arr = mit->extra_op;
        // 增加 tmp_arr 的引用计数,确保其不被释放
        Py_INCREF(tmp_arr);
        // 如果 mit->consec 为真,调用 PyArray_MapIterSwapAxes 函数交换轴
        if (mit->consec) {
            PyArray_MapIterSwapAxes(mit, &tmp_arr, 1);
            // 如果交换后 tmp_arr 为空,跳转到 fail 标签处处理错误
            if (tmp_arr == NULL) {
                goto fail;
            }
        }
        // 将 tmp_arr 的内容复制到 op 中
        if (PyArray_CopyObject(tmp_arr, op) < 0) {
             goto fail;
        }
    }

    // 检查 MapIter 对象的索引是否有效
    if (PyArray_MapIterCheckIndices(mit) < 0) {
        goto fail;
    }

    /*
     * 对齐信息(由于我们使用缓冲区,不需要交换),可以检查 extra_op 是否已缓冲,
     * 但这通常很少有影响。
     */
    int is_aligned = IsUintAligned(self) && IsUintAligned(mit->extra_op);
    // 获取迭代器的传输标志
    int meth_flags = NpyIter_GetTransferFlags(mit->outer);

    // 如果存在额外操作的迭代器
    if (mit->extra_op_iter) {
        int extra_op_flags = NpyIter_GetTransferFlags(mit->extra_op_iter);
        // 合并方法标志
        meth_flags = PyArrayMethod_COMBINED_FLAGS(meth_flags, extra_op_flags);
    }

    // 如果存在子空间迭代器
    if (mit->subspace_iter != NULL) {
        int extra_op_flags = NpyIter_GetTransferFlags(mit->subspace_iter);
        // 合并方法标志
        meth_flags = PyArrayMethod_COMBINED_FLAGS(meth_flags, extra_op_flags);

        NPY_ARRAYMETHOD_FLAGS transfer_flags;
        npy_intp fixed_strides[2];

        /*
         * 获取 dtype 传输函数,由于没有缓冲区,这是安全的。
         */
        NpyIter_GetInnerFixedStrideArray(mit->subspace_iter, fixed_strides);

        // 获取数据类型的传输函数,设置转换标志
        if (PyArray_GetDTypeTransferFunction(is_aligned,
                fixed_strides[1], fixed_strides[0],
                PyArray_DESCR(mit->extra_op), PyArray_DESCR(self),
                0, &cast_info, &transfer_flags) != NPY_SUCCEED) {
            goto fail;
        }
        // 合并方法标志
        meth_flags = PyArrayMethod_COMBINED_FLAGS(meth_flags, transfer_flags);
    }
    else {
        /* 可能需要一个通用的复制函数(仅适用于引用和奇怪的大小) */
        NPY_ARRAYMETHOD_FLAGS transfer_flags;
        npy_intp itemsize = PyArray_ITEMSIZE(self);

        // 获取数据类型的传输函数,设置转换标志
        if (PyArray_GetDTypeTransferFunction(1,
                itemsize, itemsize,
                PyArray_DESCR(self), PyArray_DESCR(self),
                0, &cast_info, &transfer_flags) != NPY_SUCCEED) {
            goto fail;
        }
        // 合并方法标志
        meth_flags = PyArrayMethod_COMBINED_FLAGS(meth_flags, transfer_flags);
    }

    // 如果方法标志不包含 NPY_METH_NO_FLOATINGPOINT_ERRORS,则清除浮点状态
    if (!(meth_flags & NPY_METH_NO_FLOATINGPOINT_ERRORS)) {
        npy_clear_floatstatus_barrier((char *)mit);
    }

    // 现在可以重置外部迭代器(延迟 bufalloc)
    if (NpyIter_Reset(mit->outer, NULL) < 0) {
        goto fail;
    }

    /*
     * 可能需要一个类型转换检查,但显然大多数赋值操作不关心安全转换。
     */
    // 如果设置 MapIter 的函数失败,则跳转到 fail 处理错误
    if (mapiter_set(mit, &cast_info, meth_flags, is_aligned) < 0) {
        goto fail;
    }

    // 如果方法标志不包含 NPY_METH_NO_FLOATINGPOINT_ERRORS,则获取浮点错误状态
    if (!(meth_flags & NPY_METH_NO_FLOATINGPOINT_ERRORS)) {
        int fpes = npy_get_floatstatus_barrier((char *)mit);
        // 如果获取到浮点错误并且处理浮点错误失败,则跳转到 fail 处理错误
        if (fpes && PyUFunc_GiveFloatingpointErrors("cast", fpes) < 0) {
            goto fail;
        }
    }
    }

    // 减少 mit 的引用计数,释放其占用的内存
    Py_DECREF(mit);
    // 跳转到成功的标签,表示函数成功执行
    goto success;

    /* Clean up temporary variables and indices */
  fail:
    // 释放视图对象的内存
    Py_XDECREF((PyObject *)view);
    // 释放临时数组对象的内存
    Py_XDECREF((PyObject *)tmp_arr);
    // 释放 mit 对象的内存
    Py_XDECREF((PyObject *)mit);
    // 释放类型转换信息结构体的内存
    NPY_cast_info_xfree(&cast_info);

    // 循环释放索引数组中每个元素对象的内存
    for (i=0; i < index_num; i++) {
        Py_XDECREF(indices[i].object);
    }
    // 返回 -1 表示执行失败
    return -1;

  success:
    // 释放视图对象的内存
    Py_XDECREF((PyObject *)view);
    // 释放临时数组对象的内存
    Py_XDECREF((PyObject *)tmp_arr);
    // 释放类型转换信息结构体的内存
    NPY_cast_info_xfree(&cast_info);

    // 循环释放索引数组中每个元素对象的内存
    for (i=0; i < index_num; i++) {
        Py_XDECREF(indices[i].object);
    }
    // 返回 0 表示执行成功
    return 0;
/*********************** Subscript Array Iterator *************************
 *                                                                        *
 * This object handles subscript behavior for array objects.              *
 * It is an iterator object with a next method                            *
 * It abstracts the n-dimensional mapping behavior to make the looping    *
 * code more understandable (maybe)                                      *
 * and so that indexing can be set up ahead of time                      *
 */

/*
 * This function takes a Boolean array and constructs index objects and
 * iterators as if nonzero(Bool) had been called
 *
 * Must not be called on a 0-d array.
 */
static int
_nonzero_indices(PyObject *myBool, PyArrayObject **arrays)
{
    PyArray_Descr *typecode;
    PyArrayObject *ba = NULL, *new = NULL;
    int nd, j;
    npy_intp size, i, count;
    npy_bool *ptr;
    npy_intp coords[NPY_MAXDIMS], dims_m1[NPY_MAXDIMS];
    npy_intp *dptr[NPY_MAXDIMS];
    static npy_intp one = 1;
    NPY_BEGIN_THREADS_DEF;

    // 创建一个描述符类型为 NPY_BOOL 的 PyArray_Descr 对象
    typecode = PyArray_DescrFromType(NPY_BOOL);
    // 从任意对象 myBool 创建一个布尔数组 ba
    ba = (PyArrayObject *)PyArray_FromAny(myBool, typecode, 0, 0,
                                          NPY_ARRAY_CARRAY, NULL);
    // 如果创建失败,返回错误码 -1
    if (ba == NULL) {
        return -1;
    }
    // 获取数组 ba 的维度数
    nd = PyArray_NDIM(ba);

    // 将数组指针初始化为空
    for (j = 0; j < nd; j++) {
        arrays[j] = NULL;
    }
    // 获取数组 ba 的总大小
    size = PyArray_SIZE(ba);
    // 获取数组 ba 的数据指针,并转换为布尔型指针
    ptr = (npy_bool *)PyArray_DATA(ba);

    /*
     * 预先确定有多少个非零条目,
     * 忽略输入的维度信息,因为它是一个 CARRAY
     */
    // 调用 count_boolean_trues 函数计算布尔数组中的真值数量
    count = count_boolean_trues(1, (char*)ptr, &size, &one);

    /* 为每个维度创建大小为 count 的索引数组 */
    for (j = 0; j < nd; j++) {
        // 创建一个新的 intp 类型数组 new,大小为 count
        new = (PyArrayObject *)PyArray_NewFromDescr(
            &PyArray_Type, PyArray_DescrFromType(NPY_INTP),
            1, &count, NULL, NULL,
            0, NULL);
        // 如果创建失败,跳转到失败标签
        if (new == NULL) {
            goto fail;
        }
        // 将新创建的数组赋值给 arrays[j]
        arrays[j] = new;

        // 获取新数组 new 的数据指针,并转换为 intp 型指针
        dptr[j] = (npy_intp *)PyArray_DATA(new);
        // 初始化坐标数组的当前维度为 0
        coords[j] = 0;
        // 将 ba 在当前维度上的最大索引保存到 dims_m1 数组中
        dims_m1[j] = PyArray_DIMS(ba)[j] - 1;
    }
    // 如果 count 为 0,直接跳转到结束标签
    if (count == 0) {
        goto finish;
    }

    /*
     * 遍历布尔数组,并复制非零条目的坐标
     */
    // 启动多线程处理,根据 size 的大小决定是否启动多线程
    NPY_BEGIN_THREADS_THRESHOLDED(size);
    // 循环遍历从 0 到 size-1 的索引 i
    for (i = 0; i < size; i++) {
        // 检查 ptr 指向的值是否为真,如果是则执行内部代码块
        if (*(ptr++)) {
            // 遍历从 0 到 nd-1 的索引 j
            for (j = 0; j < nd; j++) {
                // 将 coords[j] 的值赋给 dptr[j] 所指向的位置,并移动 dptr[j] 指针
                *(dptr[j]++) = coords[j];
            }
        }
        /* Borrowed from ITER_NEXT macro */
        // 从 nd-1 开始到 0 的索引 j 进行遍历
        for (j = nd - 1; j >= 0; j--) {
            // 如果 coords[j] 小于 dims_m1[j],则将 coords[j] 增加 1 并跳出循环
            if (coords[j] < dims_m1[j]) {
                coords[j]++;
                break;
            }
            // 否则将 coords[j] 设为 0
            else {
                coords[j] = 0;
            }
        }
    }
    NPY_END_THREADS;

finish:
    // 释放 ba 对象的引用
    Py_DECREF(ba);
    // 返回 nd 的值
    return nd;

fail:
    // 失败时释放所有 arrays[j] 的引用
    for (j = 0; j < nd; j++) {
        Py_XDECREF(arrays[j]);
    }
    // 释放 ba 对象的引用
    Py_XDECREF(ba);
    // 返回 -1 表示失败
    return -1;
/* 重置映射迭代器到开始位置 */
NPY_NO_EXPORT int
PyArray_MapIterReset(PyArrayMapIterObject *mit)
{
    npy_intp indval;  // 定义整数索引值
    char *baseptrs[2];  // 定义两个字符指针数组
    int i;  // 定义循环计数变量

    if (mit->size == 0) {  // 如果迭代器大小为0,则直接返回0
        return 0;
    }

    if (!NpyIter_Reset(mit->outer, NULL)) {  // 重置外部迭代器,如果失败则返回-1
        return -1;
    }
    if (mit->extra_op_iter) {  // 如果存在额外操作迭代器
        if (!NpyIter_Reset(mit->extra_op_iter, NULL)) {  // 重置额外操作迭代器,如果失败则返回-1
            return -1;
        }

        baseptrs[1] = mit->extra_op_ptrs[0];  // 设置第二个基础指针
    }

    baseptrs[0] = mit->baseoffset;  // 设置第一个基础指针为偏移量

    for (i = 0; i < mit->num_fancy; i++) {  // 遍历所有的特殊索引
        indval = *((npy_intp*)mit->outer_ptrs[i]);  // 获取外部指针的索引值
        if (indval < 0) {  // 如果索引值小于0,则加上特殊维度值
            indval += mit->fancy_dims[i];
        }
        baseptrs[0] += indval * mit->fancy_strides[i];  // 根据索引值和步幅计算基础指针偏移量
    }
    mit->dataptr = baseptrs[0];  // 设置数据指针为第一个基础指针

    if (mit->subspace_iter) {  // 如果存在子空间迭代器
        if (!NpyIter_ResetBasePointers(mit->subspace_iter, baseptrs, NULL)) {  // 重置子空间迭代器的基础指针,如果失败则返回-1
            return -1;
        }
        mit->iter_count = *NpyIter_GetInnerLoopSizePtr(mit->subspace_iter);  // 获取子空间迭代器的内部循环大小
    }
    else {
        mit->iter_count = *NpyIter_GetInnerLoopSizePtr(mit->outer);  // 否则获取外部迭代器的内部循环大小
    }

    return 0;  // 返回0表示成功
}


/*
 * 这个函数需要更新映射迭代器的状态,并将 mit->dataptr 指向下一个对象的内存位置
 *
 * 需要注意,此函数不处理额外操作数,但为旧的(已暴露的)API提供兼容性。
 */
NPY_NO_EXPORT void
PyArray_MapIterNext(PyArrayMapIterObject *mit)
{
    int i;  // 定义循环计数变量
    char *baseptr;  // 定义字符指针变量
    npy_intp indval;  // 定义整数索引值

    if (mit->subspace_iter) {  // 如果存在子空间迭代器
        if (--mit->iter_count > 0) {  // 如果内部循环计数大于0
            mit->subspace_ptrs[0] += mit->subspace_strides[0];  // 子空间指针加上子空间步幅
            mit->dataptr = mit->subspace_ptrs[0];  // 设置数据指针为子空间指针
            return;
        }
        else if (mit->subspace_next(mit->subspace_iter)) {  // 否则如果子空间迭代器的下一个有效
            mit->iter_count = *NpyIter_GetInnerLoopSizePtr(mit->subspace_iter);  // 获取子空间迭代器的内部循环大小
            mit->dataptr = mit->subspace_ptrs[0];  // 设置数据指针为子空间指针
        }
        else {  // 否则
            if (!mit->outer_next(mit->outer)) {  // 如果外部迭代器的下一个无效,则返回
                return;
            }

            baseptr = mit->baseoffset;  // 设置基础指针为偏移量

            for (i = 0; i < mit->num_fancy; i++) {  // 遍历所有的特殊索引
                indval = *((npy_intp*)mit->outer_ptrs[i]);  // 获取外部指针的索引值
                if (indval < 0) {  // 如果索引值小于0,则加上特殊维度值
                    indval += mit->fancy_dims[i];
                }
                baseptr += indval * mit->fancy_strides[i];  // 根据索引值和步幅计算基础指针偏移量
            }
            NpyIter_ResetBasePointers(mit->subspace_iter, &baseptr, NULL);  // 重置子空间迭代器的基础指针
            mit->iter_count = *NpyIter_GetInnerLoopSizePtr(mit->subspace_iter);  // 获取子空间迭代器的内部循环大小

            mit->dataptr = mit->subspace_ptrs[0];  // 设置数据指针为子空间指针
        }
    }
    else {
        // 如果迭代计数大于0,执行以下操作
        if (--mit->iter_count > 0) {
            // 将基础指针设置为迭代器的基础偏移量
            baseptr = mit->baseoffset;

            // 遍历所有的“花式”索引
            for (i = 0; i < mit->num_fancy; i++) {
                // 增加外部指针的步长
                mit->outer_ptrs[i] += mit->outer_strides[i];

                // 读取当前外部指针的整数值
                indval = *((npy_intp*)mit->outer_ptrs[i]);
                // 如果该值小于0,加上“花式”维度的大小
                if (indval < 0) {
                    indval += mit->fancy_dims[i];
                }
                // 基础指针加上计算出的索引值乘以“花式”步长
                baseptr += indval * mit->fancy_strides[i];
            }

            // 设置数据指针为新的基础指针位置,并返回
            mit->dataptr = baseptr;
            return;
        }
        else {
            // 如果迭代计数不大于0,检查是否可以获取下一个外部迭代器
            if (!mit->outer_next(mit->outer)) {
                // 如果无法获取下一个外部迭代器,直接返回
                return;
            }
            // 重新设置迭代计数为当前外部迭代器的内部循环大小
            mit->iter_count = *NpyIter_GetInnerLoopSizePtr(mit->outer);
            // 将基础指针设置为迭代器的基础偏移量
            baseptr = mit->baseoffset;

            // 再次遍历所有的“花式”索引
            for (i = 0; i < mit->num_fancy; i++) {
                // 读取当前外部指针的整数值
                indval = *((npy_intp*)mit->outer_ptrs[i]);
                // 如果该值小于0,加上“花式”维度的大小
                if (indval < 0) {
                    indval += mit->fancy_dims[i];
                }
                // 基础指针加上计算出的索引值乘以“花式”步长
                baseptr += indval * mit->fancy_strides[i];
            }

            // 设置数据指针为新的基础指针位置
            mit->dataptr = baseptr;
        }
    }
/**
 * Fill information about the iterator. The MapIterObject does not
 * need to have any information set for this function to work.
 * (PyArray_MapIterSwapAxes requires also nd and nd_fancy info)
 *
 * Sets the following information:
 *    * mit->consec: The axis where the fancy indices need transposing to.
 *    * mit->iteraxes: The axis which the fancy index corresponds to.
 *    * mit->fancy_dims: the dimension of `arr` along the indexed dimension
 *          for each fancy index.
 *    * mit->fancy_strides: the strides for the dimension being indexed
 *          by each fancy index.
 *    * mit->dimensions: Broadcast dimension of the fancy indices and
 *          the subspace iteration dimension.
 *
 * @param MapIterObject The iterator object to fill with information.
 * @param indices The parsed indices object containing index information.
 * @param index_num Number of indices.
 * @param arr The array that is being iterated.
 *
 * @return 0 on success, -1 on failure (broadcasting or too many fancy indices).
 */
static int
mapiter_fill_info(PyArrayMapIterObject *mit, npy_index_info *indices,
                  int index_num, PyArrayObject *arr)
{
    int j = 0, i;
    int curr_dim = 0;
    /* dimension of index result (up to first fancy index) */
    int result_dim = 0;
    /* -1 init; 0 found fancy; 1 fancy stopped; 2 found not consecutive fancy */
    int consec_status = -1;
    int axis, broadcast_axis;
    npy_intp dimension;

    // Initialize dimensions of fancy indices to 1
    for (i = 0; i < mit->nd_fancy; i++) {
        mit->dimensions[i] = 1;
    }

    // Set consec to 0
    mit->consec = 0;

    // Fill dimension of subspace if it exists
    if (mit->subspace) {
        for (i = 0; i < PyArray_NDIM(mit->subspace); i++) {
            mit->dimensions[mit->nd_fancy + i] = PyArray_DIM(mit->subspace, i);
        }
    }

    // Successful completion
    return 0;

broadcast_error: ;  // Declarations cannot follow labels, add empty statement.
    /*
     * Attempt to set a meaningful exception. Could also find out
     * if a boolean index was converted.
     */
    
    // Initialize error message
    PyObject *errmsg = PyUnicode_FromString("");
    if (errmsg == NULL) {
        return -1;
    }

    // Iterate over indices to build error message
    for (i = 0; i < index_num; i++) {
        // Skip non-fancy indices
        if (!(indices[i].type & HAS_FANCY)) {
            continue;
        }

        // Get dimensions and shape of the index object
        int ndim = PyArray_NDIM((PyArrayObject *)indices[i].object);
        npy_intp *shape = PyArray_SHAPE((PyArrayObject *)indices[i].object);
        // Convert shape information to string
        PyObject *tmp = convert_shape_to_string(ndim, shape, " ");
        if (tmp == NULL) {
            Py_DECREF(errmsg);
            return -1;
        }

        // Concatenate shape information to error message
        Py_SETREF(errmsg, PyUnicode_Concat(errmsg, tmp));
        Py_DECREF(tmp);
        if (errmsg == NULL) {
            return -1;
        }
    }

    // Format and set PyErr exception for broadcasting error
    PyErr_Format(PyExc_IndexError,
            "shape mismatch: indexing arrays could not "
            "be broadcast together with shapes %S", errmsg);
    Py_DECREF(errmsg);
    return -1;
}
# 检查索引是否符合要求的函数,针对PyArrayMapIterObject结构体的实例mit
def PyArray_MapIterCheckIndices(PyArrayMapIterObject *mit):
    # op是PyArrayObject类型的指针,用于存储当前操作的数组对象
    PyArrayObject *op;
    # op_iter是NpyIter类型的指针,用于存储操作数组的迭代器对象
    NpyIter *op_iter;
    # op_iternext是NpyIter_IterNextFunc类型的指针,用于存储操作数组迭代器的迭代函数
    NpyIter_IterNextFunc *op_iternext;
    # outer_dim是npy_intp类型的变量,表示外层维度的大小
    npy_intp outer_dim, indval;
    # outer_axis是整型变量,表示外层轴的索引
    int outer_axis;
    # itersize是npy_intp类型的变量,表示迭代器的大小
    npy_intp itersize, *iterstride;
    # iterptr是字符指针的数组,用于存储迭代器的指针
    char **iterptr;
    # intp_type是PyArray_Descr类型的指针,用于存储表示整型的数组描述符对象
    PyArray_Descr *intp_type;
    # i是整型变量,用于迭代
    int i;
    # NPY_BEGIN_THREADS_DEF宏定义,用于开启线程(Python多线程环境下使用)

    if (NpyIter_GetIterSize(mit->outer) == 0) {
        """
         * 当外层迭代为空时,索引广播到一个空形状,此时我们不检查是否存在越界索引。
         * 下面的代码在不进行广播的情况下使用索引,因为广播只是重复值。
         """
        # 返回0,表示没有越界索引的检查
        return 0;
    }

    # intp_type为NPY_INTP类型的PyArray_Descr对象,表示整型数组描述符
    intp_type = PyArray_DescrFromType(NPY_INTP);

    # 开启线程环境
    NPY_BEGIN_THREADS;
    // 遍历mit结构体中的每个fancy索引操作
    for (i=0; i < mit->num_fancy; i++) {
        // 获取当前操作数
        op = NpyIter_GetOperandArray(mit->outer)[i];

        // 获取外部维度和迭代轴
        outer_dim = mit->fancy_dims[i];
        outer_axis = mit->iteraxes[i];

        /* 查看是否可以简单迭代数组 */
        if (PyArray_TRIVIALLY_ITERABLE(op) &&
                /* 检查类型是否等同于INTP */
                PyArray_ITEMSIZE(op) == sizeof(npy_intp) &&
                PyArray_DESCR(op)->kind == 'i' &&
                IsUintAligned(op) &&
                PyDataType_ISNOTSWAPPED(PyArray_DESCR(op))) {
            char *data;
            npy_intp stride;
            /* 如果GIL被下面的nditer占用,则释放它 */
            if (_save == NULL) {
                NPY_BEGIN_THREADS;
            }

            // 准备简单迭代操作
            PyArray_PREPARE_TRIVIAL_ITERATION(op, itersize, data, stride);

            // 迭代操作数据
            while (itersize--) {
                indval = *((npy_intp*)data);
                // 检查并调整索引值
                if (check_and_adjust_index(&indval,
                                           outer_dim, outer_axis, _save) < 0) {
                    Py_DECREF(intp_type);
                    // 跳转到索引错误处理
                    goto indexing_error;
                }
                data += stride;
            }
            /* 在函数结束或需要nditer路径时重新获取GIL */
            continue;
        }

        /* 如果无法简单迭代,则使用NpyIter */
        NPY_END_THREADS;
        // 创建NpyIter对象
        op_iter = NpyIter_New(op,
                        NPY_ITER_BUFFERED | NPY_ITER_NBO | NPY_ITER_ALIGNED |
                        NPY_ITER_EXTERNAL_LOOP | NPY_ITER_GROWINNER |
                        NPY_ITER_READONLY | NPY_ITER_ZEROSIZE_OK,
                        NPY_KEEPORDER, NPY_SAME_KIND_CASTING, intp_type);

        // 检查NpyIter对象是否创建成功
        if (op_iter == NULL) {
            Py_DECREF(intp_type);
            return -1;
        }
        // 如果迭代大小为0,则释放NpyIter对象并继续下一次循环
        if (NpyIter_GetIterSize(op_iter) == 0) {
            NpyIter_Deallocate(op_iter);
            continue;
        }

        // 获取NpyIter对象的迭代器和数据指针
        op_iternext = NpyIter_GetIterNext(op_iter, NULL);
        if (op_iternext == NULL) {
            Py_DECREF(intp_type);
            NpyIter_Deallocate(op_iter);
            return -1;
        }

        // 开始多线程迭代操作
        NPY_BEGIN_THREADS_NDITER(op_iter);
        iterptr = NpyIter_GetDataPtrArray(op_iter);
        iterstride = NpyIter_GetInnerStrideArray(op_iter);
        do {
            // 获取内部循环的大小
            itersize = *NpyIter_GetInnerLoopSizePtr(op_iter);
            while (itersize--) {
                indval = *((npy_intp*)*iterptr);
                // 检查并调整索引值
                if (check_and_adjust_index(&indval,
                                           outer_dim, outer_axis, _save) < 0) {
                    Py_DECREF(intp_type);
                    NpyIter_Deallocate(op_iter);
                    // 跳转到索引错误处理
                    goto indexing_error;
                }
                *iterptr += *iterstride;
            }
        } while (op_iternext(op_iter));

        // 结束多线程迭代
        NPY_END_THREADS;
        // 释放NpyIter对象
        NpyIter_Deallocate(op_iter);
    }

    // 结束多线程迭代
    NPY_END_THREADS;
    // 释放intp_type类型对象的引用计数
    Py_DECREF(intp_type);
    // 返回成功状态
    return 0;
indexing_error:

    if (mit->size == 0) {
        // 检查迭代器的大小是否为0,即迭代结果中没有元素
        PyObject *err_type = NULL, *err_value = NULL, *err_traceback = NULL;
        // 检索最近的 Python 异常
        PyErr_Fetch(&err_type, &err_value, &err_traceback);
        /* 2020-05-27, NumPy 1.20 */
        // 发出弃用警告,说明索引越界将不再被忽略,而是引发异常
        if (DEPRECATE(
                "Out of bound index found. This was previously ignored "
                "when the indexing result contained no elements. "
                "In the future the index error will be raised. This error "
                "occurs either due to an empty slice, or if an array has zero "
                "elements even before indexing.\n"
                "(Use `warnings.simplefilter('error')` to turn this "
                "DeprecationWarning into an error and get more details on "
                "the invalid index.)") < 0) {
            // 将之前检索到的异常链入当前 Python 异常
            npy_PyErr_ChainExceptions(err_type, err_value, err_traceback);
            return -1;
        }
        // 释放异常对象的引用
        Py_DECREF(err_type);
        Py_DECREF(err_value);
        Py_XDECREF(err_traceback);
        return 0;
    }

    return -1;
}


/*
 * Create new mapiter.
 *
 * NOTE: The outer iteration (and subspace if requested buffered) is
 *       created with DELAY_BUFALLOC. It must be reset before usage!
 *
 * @param Index information filled by prepare_index.
 *        由 prepare_index 填充的索引信息
 * @param Number of indices (gotten through prepare_index).
 *        索引的数量(通过 prepare_index 获得)
 * @param Kind of index (gotten through preprare_index).
 *        索引的类型(通过 prepare_index 获得)
 * @param NpyIter flags for an extra array. If 0 assume that there is no
 *        extra operand. NPY_ITER_ALLOCATE can make sense here.
 *        用于额外数组的 NpyIter 标志。如果为 0,则假设没有额外操作数。
 *        NPY_ITER_ALLOCATE 在这里可能有意义。
 * @param Array being indexed
 *        被索引的数组
 * @param subspace (result of getting view for the indices)
 *        subspace(通过索引获取视图的结果)
 * @param Subspace iterator flags can be used to enable buffering.
 *        NOTE: When no subspace is necessary, the extra operand will
 *              always be buffered! Buffering the subspace when not
 *              necessary is very slow when the subspace is small.
 *        子空间迭代器标志可用于启用缓冲。
 *        注意:当不需要子空间时,额外操作数始终会被缓冲!
 *              当子空间很小时,缓冲子空间不必要地慢。
 * @param Subspace operand flags (should just be 0 normally)
 *        子空间操作数标志(通常应为0)
 * @param Operand iteration flags for the extra operand, this must not be
 *        0 if an extra operand should be used, otherwise it must be 0.
 *        Should be at least READONLY, WRITEONLY or READWRITE.
 *        用于额外操作数的操作数迭代标志,如果应使用额外操作数,则此值不能为0,否则必须为0。
 *        应至少为 READONLY、WRITEONLY 或 READWRITE。
 * @param Extra operand. For getmap, this would be the result, for setmap
 *        this would be the arrays to get from.
 *        Can be NULL, and will be allocated in that case. However,
 *        it matches the mapiter iteration, so you have to call
 *        MapIterSwapAxes(mit, &extra_op, 1) on it.
 *        The operand has no effect on the shape.
 *        额外的操作数。对于 getmap,这将是结果,对于 setmap,这将是要获取的数组。
 *        可以为 NULL,在这种情况下将会分配内存。但是,它匹配 mapiter 迭代,因此您必须在其上调用 MapIterSwapAxes(mit, &extra_op, 1)。
 *        操作数对形状没有影响。
 * @param Dtype for the extra operand, borrows the reference and must not
 *        be NULL (if extra_op_flags is not 0).
 *        用于额外操作数的 Dtype,借用引用并且不能为 NULL(如果 extra_op_flags 不为 0)。
 *
 * @return A new MapIter (PyObject *) or NULL.
 *         返回新的 MapIter(PyObject *)或 NULL。
 */
NPY_NO_EXPORT PyObject *
    /* 用于在错误报告中报告形状 */
    PyArrayObject *original_extra_op = extra_op;

    /* 注意:MAXARGS 是实际限制(2*NPY_MAXDIMS 是第一个索引号) */
    PyArrayObject *index_arrays[NPY_MAXDIMS];
    PyArray_Descr *intp_descr;
    PyArray_Descr *dtypes[NPY_MAXDIMS];  /* 借用的引用 */

    npy_uint32 op_flags[NPY_MAXDIMS];
    npy_uint32 outer_flags;

    PyArrayMapIterObject *mit;

    int single_op_axis[NPY_MAXDIMS];
    int *op_axes[NPY_MAXDIMS] = {NULL};
    int i, j, dummy_array = 0;
    int nops;
    int uses_subspace;

    /* 从 NPY_INTP 类型创建描述符 */
    intp_descr = PyArray_DescrFromType(NPY_INTP);
    if (intp_descr == NULL) {
        return NULL;
    }

    /* 创建新的 MapIter 对象 */
    mit = (PyArrayMapIterObject *)PyArray_malloc(
            sizeof(PyArrayMapIterObject) + sizeof(NPY_cast_info));
    if (mit == NULL) {
        Py_DECREF(intp_descr);
        return NULL;
    }
    /* 将 mapiter 的所有属性设置为零 */
    memset(mit, 0, sizeof(PyArrayMapIterObject) + sizeof(NPY_cast_info));
    PyObject_Init((PyObject *)mit, &PyArrayMapIter_Type);

    Py_INCREF(arr);
    mit->array = arr;
    Py_XINCREF(subspace);
    mit->subspace = subspace;

    /*
     * subspace 是数组未索引部分,在 subspace 大小大于 1 时需要迭代。
     * 如果大小为 1,则仅影响结果形状。(优化例如 np.newaxis 的用法)
     */
    if ((subspace == NULL) || PyArray_SIZE(subspace) == 1) {
        uses_subspace = 0;
    }
    else {
        uses_subspace = 1;
    }

    /* 填充 mapiter 的基本信息 */
    mit->nd = ndim;
    mit->nd_fancy = fancy_ndim;
    if (mapiter_fill_info(mit, indices, index_num, arr) < 0) {
        Py_DECREF(mit);
        Py_DECREF(intp_descr);
        return NULL;
    }

    /*
     * 设置索引数组的迭代信息。
     */
    for (i=0; i < index_num; i++) {
        if (indices[i].type & HAS_FANCY) {
            index_arrays[mit->num_fancy] = (PyArrayObject *)indices[i].object;
            dtypes[mit->num_fancy] = intp_descr;

            op_flags[mit->num_fancy] = (NPY_ITER_NBO |
                                      NPY_ITER_ALIGNED |
                                      NPY_ITER_READONLY);
            mit->num_fancy += 1;
        }
    }
    if (mit->num_fancy == 0) {
        /*
         * 对于 MapIterArray,可能没有使用 fancy 索引。
         * 为了支持这种情况,添加一个虚拟迭代器。
         * 由于它是零维的,其转置等操作并不重要。
         */

        /* 信号需要减少引用计数... */
        dummy_array = 1;

        // 创建一个包含零个元素的整数类型数组作为索引数组
        index_arrays[0] = (PyArrayObject *)PyArray_Zeros(0, NULL,
                                        PyArray_DescrFromType(NPY_INTP), 0);
        // 如果创建失败,释放资源并返回空指针
        if (index_arrays[0] == NULL) {
            Py_DECREF(mit);
            Py_DECREF(intp_descr);
            return NULL;
        }
        // 设置数据类型为整数类型描述符
        dtypes[0] = intp_descr;
        // 设置操作标志为字节序、对齐和只读
        op_flags[0] = NPY_ITER_NBO | NPY_ITER_ALIGNED | NPY_ITER_READONLY;

        // 设置 fancy_dims 的第一个维度为 1,并标记有 fancy 索引存在
        mit->fancy_dims[0] = 1;
        mit->num_fancy = 1;
    }

    /*
     * 现在有两种一般情况下额外操作(extra_op)的使用方式:
     *   1. 不需要子空间迭代,因此额外操作可以包含在索引迭代器中(会被缓冲)。
     *   2. 需要子空间迭代,因此额外操作会独立迭代,并且迭代顺序固定为 C 顺序
     *      (如果数组是 Fortran 顺序,也可以使用 Fortran 顺序)。
     *      在这种情况下,子空间迭代器不会被缓冲。
     *
     * 如果需要子空间迭代,并且给定了额外操作(extra_op),可能还需要对额外操作进行转置
     * (或者通知高级迭代器进行转置)。
     */
    if (extra_op != NULL) {
        /*
         * 如果存在额外操作数,需要对其进行准备。
         *   1. 子类可能会影响形状,因此需要一个基类。
         *   2. 需要确保形状是兼容的。
         *   3. 可能需要移除前导的1并转置维度。
         *      普通的赋值操作允许广播去除前导的1,但是转置代码不允许这样做。
         */
        
        if (!PyArray_CheckExact(extra_op)) {
            // 如果额外操作数不是精确的PyArray对象,将其视图化为PyArray对象
            extra_op = (PyArrayObject *)PyArray_View(extra_op, NULL,
                                                     &PyArray_Type);
            if (extra_op == NULL) {
                goto fail;
            }
        }
        else {
            // 如果额外操作数已经是精确的PyArray对象,增加其引用计数
            Py_INCREF(extra_op);
        }

        if (PyArray_NDIM(extra_op) > mit->nd) {
            /*
             * 普通赋值操作允许移除前导的单维度(或等效地添加单维度到被赋值的数组)。
             * 为了实现这一点,重新整形数组。
             */
            PyArrayObject *tmp_arr;
            PyArray_Dims permute;

            permute.len = mit->nd;
            permute.ptr = &PyArray_DIMS(extra_op)[
                                            PyArray_NDIM(extra_op) - mit->nd];
            tmp_arr = (PyArrayObject*)PyArray_Newshape(extra_op, &permute,
                                                       NPY_CORDER);
            if (tmp_arr == NULL) {
                goto broadcast_error;
            }
            Py_DECREF(extra_op);
            extra_op = tmp_arr;
        }

        /*
         * 如果需要前置维度(并且不需要swapaxis),在确保分配额外操作数后使用op_axes。
         */
        if (mit->consec) {
            PyArray_MapIterSwapAxes(mit, &extra_op, 0);
            if (extra_op == NULL) {
                goto fail;
            }
        }

        if (subspace && !uses_subspace) {
            /*
             * 我们没有使用子空间,因此其大小为1。
             * 额外操作数对应于子空间的所有维度必须等于1。
             */
            if (PyArray_NDIM(subspace) <= PyArray_NDIM(extra_op)) {
                j = PyArray_NDIM(subspace);
            }
            else {
                j = PyArray_NDIM(extra_op);
            }
            for (i = 1; i < j + 1; i++) {
                if (PyArray_DIM(extra_op, PyArray_NDIM(extra_op) - i) != 1) {
                    goto broadcast_error;
                }
            }
        }
    }

    /*
     * 如果子空间不为NULL,NpyIter不能为我们分配额外操作数。
     * 这有点笨拙。创建一个虚拟迭代器来找到正确的输出形状和步幅排列。
     * TODO: 这可以至少部分地被替换,因为形状已经找到以处理广播错误。
     */
        else if (extra_op_flags && (subspace != NULL)) {
            # 如果额外操作标志位非零且子空间非空

            npy_uint32 tmp_op_flags[NPY_MAXDIMS];
            # 声明一个用于临时操作标志的数组,长度为最大维度数

            NpyIter *tmp_iter;
            # 声明一个 NpyIter 指针变量

            npy_intp stride;
            npy_intp strides[NPY_MAXDIMS];
            # 声明一个步幅和一个步幅数组,长度均为最大维度数

            npy_stride_sort_item strideperm[NPY_MAXDIMS];
            # 声明一个用于步幅排序的结构体数组,长度为最大维度数

            for (i=0; i < mit->num_fancy; i++) {
                tmp_op_flags[i] = NPY_ITER_READONLY;
                # 初始化临时操作标志数组,所有元素设置为 NPY_ITER_READONLY
            }

            if (PyArray_SIZE(subspace) == 1) {
                /* Create an iterator, just to broadcast the arrays?! */
                # 如果子空间大小为1,创建一个迭代器,用于广播数组?!

                tmp_iter = NpyIter_MultiNew(mit->num_fancy, index_arrays,
                                            NPY_ITER_ZEROSIZE_OK |
                                            NPY_ITER_REFS_OK |
                                            NPY_ITER_MULTI_INDEX |
                                            NPY_ITER_DONT_NEGATE_STRIDES,
                                            NPY_KEEPORDER,
                                            NPY_UNSAFE_CASTING,
                                            tmp_op_flags, NULL);
                # 使用 NpyIter_MultiNew 函数创建一个多迭代器
                # 设置迭代器的选项包括 NPY_ITER_ZEROSIZE_OK,NPY_ITER_REFS_OK,
                # NPY_ITER_MULTI_INDEX 和 NPY_ITER_DONT_NEGATE_STRIDES
                # 还传入了临时操作标志数组和空指针作为额外参数

                if (tmp_iter == NULL) {
                    goto fail;
                    # 如果迭代器创建失败,则跳转到 fail 标签处处理错误
                }

                /*
                 * nditer allows itemsize with npy_intp type, so it works
                 * here, but it would *not* work directly, since elsize
                 * is limited to int.
                 */
                # nditer 允许使用 npy_intp 类型的 itemsize,所以这里可以工作
                # 但直接使用时不会工作,因为 elsize 限制为 int 类型

                if (!NpyIter_CreateCompatibleStrides(tmp_iter,
                            extra_op_dtype->elsize * PyArray_SIZE(subspace),
                            strides)) {
                    PyErr_SetString(PyExc_ValueError,
                            "internal error: failed to find output array strides");
                    goto fail;
                    # 如果无法创建兼容的步幅,则设置异常并跳转到 fail 标签处处理错误
                }
                NpyIter_Deallocate(tmp_iter);
                # 释放迭代器资源
            }
            else {
                /* Just use C-order strides (TODO: allow also F-order) */
                # 否则,使用 C 阶序的步幅(TODO:也允许 F 阶序)

                stride = extra_op_dtype->elsize * PyArray_SIZE(subspace);
                # 计算步幅为额外操作数据类型的元素大小乘以子空间大小

                for (i=mit->nd_fancy - 1; i >= 0; i--) {
                    strides[i] = stride;
                    stride *= mit->dimensions[i];
                    # 根据迭代器的高级维度计算步幅数组
                }
            }

            /* shape is set, and strides is set up to mit->nd, set rest */
            # 设置形状和步幅到 mit->nd,设置剩余部分

            PyArray_CreateSortedStridePerm(PyArray_NDIM(subspace),
                                    PyArray_STRIDES(subspace), strideperm);
            # 使用子空间的维度和步幅,以及步幅排序结构体数组,创建排好序的步幅排列

            stride = extra_op_dtype->elsize;
            # 步幅设置为额外操作数据类型的元素大小

            for (i=PyArray_NDIM(subspace) - 1; i >= 0; i--) {
                strides[mit->nd_fancy + strideperm[i].perm] = stride;
                stride *= PyArray_DIM(subspace, (int)strideperm[i].perm);
                # 根据排序后的步幅排列,计算最终的步幅数组
            }

            /*
             * Allocate new array. Note: Always base class, because
             * subclasses might mess with the shape.
             */
            # 分配新的数组。注意:始终使用基类,因为子类可能会改变形状。

            Py_INCREF(extra_op_dtype);
            # 增加额外操作数据类型的引用计数

            extra_op = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type,
                                               extra_op_dtype,
                                               mit->nd_fancy + PyArray_NDIM(subspace),
                                               mit->dimensions, strides,
                                               NULL, 0, NULL);
            # 使用 PyArray_NewFromDescr 函数创建一个新的数组对象
            # 设置对象类型为 PyArray_Type,传入额外操作数据类型、维度数、形状、步幅等参数

            if (extra_op == NULL) {
                goto fail;
                # 如果创建数组对象失败,则跳转到 fail 标签处处理错误
            }
        }
    /*
     * 如果额外操作 extra_op 存在,则要么已分配,可以由 NpyIter 分配(无子空间),或者根本未使用。
     * 需要为 extra_op 设置轴重映射。这将导致忽略子空间维度,并在广播时添加 -1。
     */
    if (extra_op) {
        for (j=0; j < mit->nd - PyArray_NDIM(extra_op); j++) {
            single_op_axis[j] = -1;  // 将 -1 添加到轴映射中,以忽略子空间维度
        }
        for (i=0; i < PyArray_NDIM(extra_op); i++) {
            /* (填充子空间维度,但它们不是未使用的)*/
            single_op_axis[j++] = i;  // 将额外操作的轴映射添加到数组末尾
        }
    }

    /*
     * 注意:如果出于某种原因有人希望使用 REDUCE_OK,请小心并修复末尾的错误消息替换。
     */
    outer_flags = NPY_ITER_ZEROSIZE_OK |
                  NPY_ITER_REFS_OK |
                  NPY_ITER_BUFFERED |
                  NPY_ITER_DELAY_BUFALLOC |
                  NPY_ITER_GROWINNER;

    /*
     * 对于单个一维操作数,保证迭代顺序(scipy 使用这个)。注意子空间可能被使用。
     */
    if ((mit->num_fancy == 1) && (PyArray_NDIM(index_arrays[0]) == 1)) {
        outer_flags |= NPY_ITER_DONT_NEGATE_STRIDES;  // 设置不反转步长的标志
    }

    /* 如果外部数组被迭代,并且不需要子空间 */
    nops = mit->num_fancy;  // 设置操作数的数量

    if (!uses_subspace) {
        outer_flags |= NPY_ITER_EXTERNAL_LOOP;  // 设置外部循环标志
    }

    if (extra_op_flags && !uses_subspace) {
        /*
         * 注意:这个小限制实际上应该没有关系。
         *       (替换 npyiter 错误)
         */
        if (mit->num_fancy > NPY_MAXDIMS - 1) {
            PyErr_Format(PyExc_IndexError,
                         "when no subspace is given, the number of index "
                         "arrays cannot be above %d, but %d index arrays found",
                         NPY_MAXDIMS - 1, mit->num_fancy);
            goto fail;  // 如果索引数组数量超过限制,触发错误并跳转到失败处理
        }

        nops += 1;  // 增加操作数的数量
        index_arrays[mit->num_fancy] = extra_op;  // 设置额外操作的索引数组

        dtypes[mit->num_fancy] = extra_op_dtype;  // 设置额外操作的数据类型
        op_flags[mit->num_fancy] = (extra_op_flags |
                                  NPY_ITER_ALLOCATE |
                                  NPY_ITER_NO_SUBTYPE);  // 设置额外操作的标志

        if (extra_op) {
            /* 使用轴重映射 */
            op_axes[mit->num_fancy] = single_op_axis;  // 设置额外操作的轴映射
            mit->outer = NpyIter_AdvancedNew(nops, index_arrays, outer_flags,
                             NPY_KEEPORDER, NPY_UNSAFE_CASTING, op_flags, dtypes,
                             mit->nd_fancy, op_axes, mit->dimensions, 0);  // 创建高级迭代器
        }
        else {
            mit->outer = NpyIter_MultiNew(nops, index_arrays, outer_flags,
                             NPY_KEEPORDER, NPY_UNSAFE_CASTING, op_flags, dtypes);  // 创建多迭代器
        }

    }
    else {
        /* TODO: 可能添加 CORDER 的测试,并且也许允许 F */
        mit->outer = NpyIter_MultiNew(nops, index_arrays, outer_flags,
                         NPY_CORDER, NPY_UNSAFE_CASTING, op_flags, dtypes);  // 创建多迭代器
    }
    /* NpyIter cleanup and information: */
    // 如果 dummy_array 存在,则减少 index_arrays[0] 的引用计数
    if (dummy_array) {
        Py_DECREF(index_arrays[0]);
    }
    // 如果 mit->outer 为 NULL,则跳转到失败标签
    if (mit->outer == NULL) {
        goto fail;
    }

    // 获取 mit->outer 的下一个迭代器函数
    mit->outer_next = NpyIter_GetIterNext(mit->outer, NULL);
    // 如果获取失败,则跳转到失败标签
    if (mit->outer_next == NULL) {
        goto fail;
    }
    // 获取 mit->outer 的数据指针数组
    mit->outer_ptrs = NpyIter_GetDataPtrArray(mit->outer);
    // 如果不使用子空间,则获取 mit->outer 的内部步幅数组
    if (!uses_subspace) {
        mit->outer_strides = NpyIter_GetInnerStrideArray(mit->outer);
    }

    /* Get the allocated extra_op */
    // 如果 extra_op_flags 存在
    if (extra_op_flags) {
        // 如果 extra_op 为 NULL,则将 mit->extra_op 设置为 mit->outer 的操作数数组中的第 mit->num_fancy 个操作数
        if (extra_op == NULL) {
            mit->extra_op = NpyIter_GetOperandArray(mit->outer)[mit->num_fancy];
        }
        else {
            // 否则,将 mit->extra_op 设置为 extra_op
            mit->extra_op = extra_op;
        }
        // 增加 mit->extra_op 的引用计数
        Py_INCREF(mit->extra_op);
    }

    /*
     * If extra_op is being tracked but subspace is used, we need
     * to create a dedicated iterator for the outer iteration of
     * the extra operand.
     */
    // 如果 extra_op_flags 存在并且使用子空间
    if (extra_op_flags && uses_subspace) {
        // 设置操作轴数组中的第一个元素为 single_op_axis
        op_axes[0] = single_op_axis;
        // 创建 mit->extra_op_iter 作为 mit->extra_op 的高级新迭代器
        mit->extra_op_iter = NpyIter_AdvancedNew(1, &extra_op,
                                                 NPY_ITER_ZEROSIZE_OK |
                                                 NPY_ITER_REFS_OK |
                                                 NPY_ITER_GROWINNER,
                                                 NPY_CORDER,
                                                 NPY_NO_CASTING,
                                                 &extra_op_flags,
                                                 NULL,
                                                 mit->nd_fancy, op_axes,
                                                 mit->dimensions, 0);

        // 如果创建失败,则跳转到失败标签
        if (mit->extra_op_iter == NULL) {
            goto fail;
        }

        // 获取 mit->extra_op_iter 的下一个迭代器函数
        mit->extra_op_next = NpyIter_GetIterNext(mit->extra_op_iter, NULL);
        // 如果获取失败,则跳转到失败标签
        if (mit->extra_op_next == NULL) {
            goto fail;
        }
        // 获取 mit->extra_op_iter 的数据指针数组
        mit->extra_op_ptrs = NpyIter_GetDataPtrArray(mit->extra_op_iter);
    }

    /* Get the full dimension information */
    // 如果 subspace 不为 NULL,则将 mit->baseoffset 设置为 subspace 的字节偏移量
    if (subspace != NULL) {
        mit->baseoffset = PyArray_BYTES(subspace);
    }
    else {
        // 否则,将 mit->baseoffset 设置为 arr 的字节偏移量
        mit->baseoffset = PyArray_BYTES(arr);
    }

    /* Calculate total size of the MapIter */
    // 计算 MapIter 的总大小
    mit->size = PyArray_OverflowMultiplyList(mit->dimensions, mit->nd);
    // 如果计算结果为负数,则设置异常并跳转到失败标签
    if (mit->size < 0) {
        PyErr_SetString(PyExc_ValueError,
                        "advanced indexing operation result is too large");
        goto fail;
    }

    /* Can now return early if no subspace is being used */
    // 如果不使用子空间,则减少 extra_op 和 intp_descr 的引用计数,并返回 mit 指针
    if (!uses_subspace) {
        Py_XDECREF(extra_op);
        Py_DECREF(intp_descr);
        return (PyObject *)mit;
    }

    /* Fill in the last bit of mapiter information needed */

    /*
     * Now just need to create the correct subspace iterator.
     */
    // 将 index_arrays[0] 设置为 subspace,并初始化其他相关变量
    index_arrays[0] = subspace;
    dtypes[0] = NULL;
    op_flags[0] = subspace_flags;
    op_axes[0] = NULL;
    if (extra_op_flags) {
        /* 如果存在额外操作标志,表示需要迭代额外操作 */
        nops = 2;
        index_arrays[1] = extra_op;  // 将额外操作数组加入索引数组中

        op_axes[1] = &single_op_axis[mit->nd_fancy];  // 设置额外操作的轴

        /*
         * Buffering is never used here, but in case someone plugs it in
         * somewhere else, set the type correctly then.
         */
        // 如果启用了缓冲,设置额外操作的数据类型
        if ((subspace_iter_flags & NPY_ITER_BUFFERED)) {
            dtypes[1] = extra_op_dtype;
        }
        else {
            dtypes[1] = NULL;  // 否则将数据类型设为 NULL
        }
        op_flags[1] = extra_op_flags;  // 设置额外操作的操作标志
    }
    else {
        nops = 1;  // 如果不存在额外操作,设置操作数为 1
    }

    // 创建高级迭代器对象,用于处理索引操作
    mit->subspace_iter = NpyIter_AdvancedNew(nops, index_arrays,
                                    NPY_ITER_ZEROSIZE_OK |
                                    NPY_ITER_REFS_OK |
                                    NPY_ITER_GROWINNER |
                                    NPY_ITER_EXTERNAL_LOOP |
                                    NPY_ITER_DELAY_BUFALLOC |
                                    subspace_iter_flags,
                                    (nops == 1 ? NPY_CORDER : NPY_KEEPORDER),
                                    NPY_UNSAFE_CASTING,
                                    op_flags, dtypes,
                                    PyArray_NDIM(subspace), op_axes,
                                    &mit->dimensions[mit->nd_fancy], 0);

    // 检查迭代器对象是否创建成功
    if (mit->subspace_iter == NULL) {
        goto fail;  // 如果创建失败,跳转到失败处理
    }

    // 获取迭代器的下一个迭代函数
    mit->subspace_next = NpyIter_GetIterNext(mit->subspace_iter, NULL);
    // 检查获取下一个迭代函数是否成功
    if (mit->subspace_next == NULL) {
        goto fail;  // 如果获取失败,跳转到失败处理
    }
    // 获取迭代器的数据指针数组
    mit->subspace_ptrs = NpyIter_GetDataPtrArray(mit->subspace_iter);
    // 获取迭代器的内部步长数组
    mit->subspace_strides = NpyIter_GetInnerStrideArray(mit->subspace_iter);

    // 减少额外操作的引用计数
    Py_XDECREF(extra_op);
    // 减少 intp 描述符的引用计数
    Py_DECREF(intp_descr);
    // 返回迭代器对象指针,表示成功
    return (PyObject *)mit;

  fail:
    /*
     * Check whether the operand could not be broadcast and replace the error
     * in that case. This should however normally be found early with a
     * direct goto to broadcast_error
     */
    // 检查是否无法对操作数进行广播,并在这种情况下替换错误
    if (extra_op == NULL) {
        goto finish;  // 如果额外操作为 NULL,跳转到结束处理
    }

    // 逆序检查额外操作的维度是否可以广播到索引结果
    j = mit->nd;
    for (i = PyArray_NDIM(extra_op) - 1; i >= 0; i--) {
        j--;
        if ((PyArray_DIM(extra_op, i) != 1) &&
                /* (j < 0 is currently impossible, extra_op is reshaped) */
                j >= 0 &&
                PyArray_DIM(extra_op, i) != mit->dimensions[j]) {
            /* extra_op cannot be broadcast to the indexing result */
            goto broadcast_error;  // 如果无法广播,跳转到广播错误处理
        }
    }
    goto finish;  // 检查完成,跳转到结束处理

  broadcast_error:
    /* Report the shape of the original array if it exists */
    // 如果存在原始数组,报告其形状
    if (original_extra_op == NULL) {
        original_extra_op = extra_op;  // 如果原始额外操作为 NULL,设置为额外操作
    }

    // 获取原始额外操作的维度信息
    int extra_ndim = PyArray_NDIM(original_extra_op);
    npy_intp *extra_dims = PyArray_DIMS(original_extra_op);
    // 将维度转换为字符串形式
    PyObject *shape1 = convert_shape_to_string(extra_ndim, extra_dims, "");
    // 如果转换失败,跳转到结束处理
    if (shape1 == NULL) {
        goto finish;
    }

    // 在使用 `mit->consec` 时,反转迭代器形状以进行报告
    npy_intp transposed[NPY_MAXDIMS];
    // 使用自定义函数获取转置操作后的索引数组,此处mit->nd_fancy可能是用于描述高级索引的数据结构
    _get_transpose(mit->nd_fancy, mit->consec, mit->nd, 1, transposed);

    // 根据转置后的索引数组,获取相应维度的大小,存储在transposed数组中
    for (i = 0; i < mit->nd; i++) {
        transposed[i] = mit->dimensions[transposed[i]];
    }

    // 将转置后的维度信息转换为字符串表示形式,用于错误信息中的格式化输出
    PyObject *shape2 = convert_shape_to_string(mit->nd, transposed, "");
    if (shape2 == NULL) {
        // 如果转换失败,释放shape1并跳转到finish标签处
        Py_DECREF(shape1);
        goto finish;
    }

    // 格式化错误信息,指示形状不匹配的问题,包括value array的形状和索引结果的形状
    PyErr_Format(PyExc_ValueError,
            "shape mismatch: value array of shape %S could not be broadcast "
            "to indexing result of shape %S", shape1, shape2);

    // 释放shape1和shape2对象
    Py_DECREF(shape1);
    Py_DECREF(shape2);

  finish:
    // 释放额外操作对象、整数描述对象和mit对象
    Py_XDECREF(extra_op);
    Py_DECREF(intp_descr);
    Py_DECREF(mit);
    // 返回NULL表示函数执行失败
    return NULL;
# 关闭函数的定义
}

# 利用高级索引来迭代数组。
# 如果 copy_if_overlap != 0,则检查 `a` 是否与 `index` 中的任何数组以及 `extra_op` 存在内存重叠。如果是,适当进行复制以避免在迭代期间修改 `a` 时出现问题。
# `iter->array` 可能包含已复制的数组(设置了 WRITEBACKIFCOPY)。
NPY_NO_EXPORT PyObject *
PyArray_MapIterArrayCopyIfOverlap(PyArrayObject * a, PyObject * index,
                                  int copy_if_overlap, PyArrayObject *extra_op)
{
    PyArrayMapIterObject * mit = NULL;  # 初始化 PyArrayMapIterObject 指针
    PyArrayObject *subspace = NULL;  # 初始化 PyArrayObject 指针
    npy_index_info indices[NPY_MAXDIMS * 2 + 1];  # 创建索引信息数组
    int i, index_num, ndim, fancy_ndim, index_type;  # 初始化整型变量
    PyArrayObject *a_copy = NULL;  # 初始化 PyArrayObject 指针

    index_type = prepare_index(a, index, indices, &index_num,  # 调用 prepare_index 函数准备索引
                               &ndim, &fancy_ndim, 0);

    if (index_type < 0) {  # 如果索引类型小于0,则返回NULL
        return NULL;
    }

    if (copy_if_overlap && index_has_memory_overlap(a, index_type, indices,  # 如果需要复制且存在内存重叠
                                                    index_num,
                                                    (PyObject *)extra_op)) {
        /* Make a copy of the input array */
        a_copy = (PyArrayObject *)PyArray_NewLikeArray(a, NPY_ANYORDER,  # 创建输入数组的副本
                                                       NULL, 0);
        if (a_copy == NULL) {
            goto fail;
        }

        if (PyArray_CopyInto(a_copy, a) != 0) {  # 如果复制失败,则跳转到失败
            goto fail;
        }

        Py_INCREF(a);  # 增加input数组的引用计数
        if (PyArray_SetWritebackIfCopyBase(a_copy, a) < 0) {  # 如果设置WRITEBACKIFCOPY出错,则跳转到失败
            goto fail;
        }

        a = a_copy;  # 将input数组指向副本
    }

    # 如果不是纯粹的fancy索引,需要获取子空间
    if (index_type != HAS_FANCY) {
        if (get_view_from_index(a, &subspace, indices, index_num, 1) < 0) {  # 如果获取子空间出现错误,则跳转到失败
            goto fail;
        }
    }

    # 创建MapIter对象
    mit = (PyArrayMapIterObject *)PyArray_MapIterNew(indices, index_num,
                                                     index_type, ndim,
                                                     fancy_ndim,
                                                     a, subspace, 0,
                                                     NPY_ITER_READWRITE,
                                                     0, NULL, NULL);
    if (mit == NULL) {  # 如果创建MapIter对象出现错误,则跳转到失败
        goto fail;
    }

    if (PyArray_MapIterCheckIndices(mit) < 0) {  # 检查MapIter的索引
        goto fail;
    }

    if (PyArray_MapIterReset(mit) < 0) {  # 重置MapIter
        goto fail;
    }

    Py_XDECREF(a_copy);  # 释放内存
    Py_XDECREF(subspace);  # 释放内存

    for (i=0; i < index_num; i++) {  # 释放索引对象的内存
        Py_XDECREF(indices[i].object);
    }

    return (PyObject *)mit;  # 返回mit对象

 fail:  # 失败时释放所有分配的内存
    Py_XDECREF(a_copy);  # 释放内存
    Py_XDECREF(subspace);  # 释放内存
    Py_XDECREF((PyObject *)mit);  # 释放内存
    for (i = 0; i < index_num; i++) {  # 释放索引对象的内存
        Py_XDECREF(indices[i].object);
    }
    return NULL;  # 返回NULL
}


# 取消定义多个宏
#undef HAS_INTEGER
#undef HAS_NEWAXIS
#undef HAS_SLICE
#undef HAS_ELLIPSIS
#undef HAS_FANCY
#undef HAS_BOOL
#undef HAS_SCALAR_ARRAY
#undef HAS_0D_BOOL


static void  # 静态函数定义
arraymapiter_dealloc(PyArrayMapIterObject *mit)  # arraymapiter_dealloc函数需要PyArrayMapIterObject指针作为参数
    # 解析并解决可能存在的写回副本问题
    PyArray_ResolveWritebackIfCopy(mit->array);
    # 释放 mit 结构体中的 array 成员的引用
    Py_XDECREF(mit->array);
    # 释放 mit 结构体中的 subspace 成员的引用
    Py_XDECREF(mit->subspace);
    # 释放 mit 结构体中的 extra_op 成员的引用
    Py_XDECREF(mit->extra_op);
    # 如果 mit 结构体中的 outer 成员不为 NULL,则释放其内存空间
    if (mit->outer != NULL) {
        NpyIter_Deallocate(mit->outer);
    }
    # 如果 mit 结构体中的 subspace_iter 成员不为 NULL,则释放其内存空间
    if (mit->subspace_iter != NULL) {
        NpyIter_Deallocate(mit->subspace_iter);
    }
    # 如果 mit 结构体中的 extra_op_iter 成员不为 NULL,则释放其内存空间
    if (mit->extra_op_iter != NULL) {
        NpyIter_Deallocate(mit->extra_op_iter);
    }
    # 释放 mit 结构体本身占用的内存空间
    PyArray_free(mit);
/*
 * The mapiter object must be created new each time.  It does not work
 * to bind to a new array, and continue.
 *
 * This comment explains that the `mapiter` object in NumPy must be 
 * instantiated anew for each use. Attempting to rebind it to a new 
 * array and continue using it does not function correctly.
 */

/*
 * This was the original intention, but currently that does not work.
 * Do not expose the MapIter_Type to Python.
 *
 * This comment notes that the original design intention to expose 
 * `MapIter_Type` to Python has been abandoned due to current 
 * functionality issues.
 */

/*
 * The original mapiter(indexobj); mapiter.bind(a); idea is now fully
 * removed. This is not very useful anyway, since mapiter is equivalent
 * to a[indexobj].flat but the latter gets to use slice syntax.
 *
 * This comment clarifies that the concept of using `mapiter(indexobj); 
 * mapiter.bind(a);` has been completely removed from the implementation. 
 * It states that using `mapiter` was not particularly useful compared 
 * to `a[indexobj].flat`, which benefits from more readable slice syntax.
 */
NPY_NO_EXPORT PyTypeObject PyArrayMapIter_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "numpy.mapiter",
    .tp_basicsize = sizeof(PyArrayMapIterObject),
    .tp_dealloc = (destructor)arraymapiter_dealloc,
    .tp_flags = Py_TPFLAGS_DEFAULT,
};