NumPy-源码解析-六十-

50 阅读27分钟

NumPy 源码解析(六十)

.\numpy\numpy\_core\src\multiarray\common_dtype.c

/*
 * 定义以下宏,以确保使用 NumPy 的最新 API 版本并禁用过时的 API。
 * _MULTIARRAYMODULE 是为了在编译期间定义多维数组模块。
 */
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
#define _MULTIARRAYMODULE

/*
 * 引入必要的头文件和库文件。
 */
#define PY_SSIZE_T_CLEAN
#include <Python.h>

#include "numpy/npy_common.h"
#include "numpy/arrayobject.h"

#include "convert_datatype.h"
#include "dtypemeta.h"
#include "abstractdtypes.h"
#include "npy_static_data.h"

/*
 * 该文件定义了通用的“common dtype”操作逻辑。
 * 这是复杂的,因为 NumPy 使用基于值的逻辑,并且没有明确的类型提升层次结构。
 * 不像大多数语言中的 `int32 + float32 -> float64`,而是变为 `float32`。
 * 另一个复杂的地方是基于值的提升,这意味着在许多情况下,Python 1 可能会成为 `int8` 或 `uint8`。
 *
 * 该文件实现了必要的逻辑,以便 `np.result_type(...)` 可以针对任何输入顺序给出正确的结果,并可以进一步推广到用户 DTypes。
 */

/*NUMPY_API
 * 该函数定义了通用的 DType 运算符。
 *
 * 注意,通用的 DType 不会是 "object"(除非其中一个 DType 是 object),即使 object 可以在技术上正确表示所有值。
 * 类似于 `np.result_type`,但适用于类而不是实例。
 *
 * TODO: 在暴露之前,我们应该审查返回值(例如,当没有找到通用的 DType 时不应报错)。
 *
 * @param dtype1 要找到通用类型的第一个 DType 类。
 * @param dtype2 第二个 DType 类。
 * @return 通用的 DType 或者 NULL 并设置错误。
 */
NPY_NO_EXPORT PyArray_DTypeMeta *
PyArray_CommonDType(PyArray_DTypeMeta *dtype1, PyArray_DTypeMeta *dtype2)
{
    // 如果 dtype1 等于 dtype2,则增加引用计数并返回 dtype1
    if (dtype1 == dtype2) {
        Py_INCREF(dtype1);
        return dtype1;
    }

    PyArray_DTypeMeta *common_dtype;

    // 调用 NPY_DT_CALL_common_dtype 函数尝试找到 dtype1 和 dtype2 的通用 DType
    common_dtype = NPY_DT_CALL_common_dtype(dtype1, dtype2);
    // 如果未找到通用 DType,则尝试反转参数顺序再次查找
    if (common_dtype == (PyArray_DTypeMeta *)Py_NotImplemented) {
        Py_DECREF(common_dtype);
        common_dtype = NPY_DT_CALL_common_dtype(dtype2, dtype1);
    }
    // 如果仍然未找到通用 DType,则返回 NULL
    if (common_dtype == NULL) {
        return NULL;
    }
    // 如果找到了 Py_NotImplemented,表示 dtype1 和 dtype2 没有通用 DType
    if (common_dtype == (PyArray_DTypeMeta *)Py_NotImplemented) {
        Py_DECREF(Py_NotImplemented);
        // 报错并返回 NULL,指示没有找到通用 DType
        PyErr_Format(npy_static_pydata.DTypePromotionError,
                "The DTypes %S and %S do not have a common DType. "
                "For example they cannot be stored in a single array unless "
                "the dtype is `object`.", dtype1, dtype2);
        return NULL;
    }
    // 返回找到的通用 DType
    return common_dtype;
}
/**
 * This function takes a list of dtypes and "reduces" them (in a sense,
 * it finds the maximal dtype). Note that "maximum" here is defined by
 * knowledge (or category or domain). A user DType must always "know"
 * about all NumPy dtypes, floats "know" about integers, integers "know"
 * about unsigned integers.
 *
 *           c
 *          / \
 *         a   \    <-- The actual promote(a, b) may be c or unknown.
 *        / \   \
 *       a   b   c
 *
 * The reduction is done "pairwise". In the above `a.__common_dtype__(b)`
 * has a result (so `a` knows more) and `a.__common_dtype__(c)` returns
 * NotImplemented (so `c` knows more).  You may notice that the result
 * `res = a.__common_dtype__(b)` is not important.  We could try to use it
 * to remove the whole branch if `res is c` or by checking if
 * `c.__common_dtype__(res) is c`.
 * Right now, we only clear initial elements in the most simple case where
 * `a.__common_dtype__(b) is a` (and thus `b` cannot alter the end-result).
 * Clearing means, we do not have to worry about them later.
 *
 * Abstract dtypes are not handled specially here.  In a first
 * version they were but this version also tried to be able to do value-based
 * behavior.
 * There may be some advantage to special casing the abstract ones (e.g.
 * so that the concrete ones do not have to deal with it), but this would
 * require more complex handling later on. See the logic in
 * default_builtin_common_dtype
 *
 * @param length Number of DTypes
 * @param dtypes List of DTypes
 */
static PyArray_DTypeMeta *
reduce_dtypes_to_most_knowledgeable(
        npy_intp length, PyArray_DTypeMeta **dtypes)
{
    assert(length >= 2); // Ensure the length is at least 2

    npy_intp half = length / 2; // Calculate the half of the length

    PyArray_DTypeMeta *res = NULL; // Initialize the result as NULL

    for (npy_intp low = 0; low < half; low++) { // Loop through the first half of the length
        npy_intp high = length - 1 - low; // Calculate the index of the opposite element
        if (dtypes[high] == dtypes[low]) { // Check if the dtypes at the high and low indices are the same
            /* Fast path for identical dtypes: do not call common_dtype */
            Py_INCREF(dtypes[low]); // Increment the reference count of dtypes[low]
            Py_XSETREF(res, dtypes[low]); // Set res to dtypes[low]
        }
        else {
            Py_XSETREF(res, NPY_DT_CALL_common_dtype(dtypes[low], dtypes[high])); // Set res to the common dtype of dtypes[low] and dtypes[high]
            if (res == NULL) { // If res is NULL
                return NULL; // Return NULL
            }
        }

        if (res == (PyArray_DTypeMeta *)Py_NotImplemented) { // Check if res is Py_NotImplemented
            /* guess at other being more "knowledgable" */
            PyArray_DTypeMeta *tmp = dtypes[low]; // Temporarily store dtypes[low]
            dtypes[low] = dtypes[high]; // Set dtypes[low] to dtypes[high]
            dtypes[high] = tmp; // Set dtypes[high] to the temporary value
        }
        else if (res == dtypes[low]) { // Check if res is equal to dtypes[low]
            /* `dtypes[high]` cannot influence result: clear */
            dtypes[high] = NULL; // Set dtypes[high] to NULL
        }
    }

    if (length == 2) { // If the length is 2
        return res; // Return res
    }
    Py_DECREF(res); // Decrease the reference count of res
    return reduce_dtypes_to_most_knowledgeable(length - half, dtypes); // Recursively call the function with the updated length and dtypes
}
/*NUMPY_API
 * Promotes a list of DTypes with each other in a way that should guarantee
 * stable results even when changing the order.  This function is smarter and
 * can often return successful and unambiguous results when
 * `common_dtype(common_dtype(dt1, dt2), dt3)` would depend on the operation
 * order or fail.  Nevertheless, DTypes should aim to ensure that their
 * common-dtype implementation is associative and commutative!  (Mainly,
 * unsigned and signed integers are not.)
 *
 * For guaranteed consistent results DTypes must implement common-Dtype
 * "transitively".  If A promotes B and B promotes C, than A must generally
 * also promote C; where "promotes" means implements the promotion.  (There
 * are some exceptions for abstract DTypes)
 *
 * In general this approach always works as long as the most generic dtype
 * is either strictly larger, or compatible with all other dtypes.
 * For example promoting float16 with any other float, integer, or unsigned
 * integer again gives a floating point number. And any floating point number
 * promotes in the "same way" as `float16`.
 * If a user inserts more than one type into the NumPy type hierarchy, this
 * can break. Given:
 *     uint24 + int32 -> int48  # Promotes to a *new* dtype!
 *
 * The following becomes problematic (order does not matter):
 *         uint24 +      int16  +           uint32  -> int64
 *    <==      (uint24 + int16) + (uint24 + uint32) -> int64
 *    <==                int32  +           uint32  -> int64
 *
 * It is impossible to achieve an `int48` result in the above.
 *
 * This is probably only resolvable by asking `uint24` to take over the
 * whole reduction step; which we currently do not do.
 * (It may be possible to notice the last up-cast and implement use something
 * like: `uint24.nextafter(int32).__common_dtype__(uint32)`, but that seems
 * even harder to grasp.)
 *
 * Note that a case where two dtypes are mixed (and know nothing about each
 * other) will always generate an error:
 *     uint24 + int48 + int64 -> Error
 *
 * Even though `int64` is a safe solution, since `uint24 + int64 -> int64` and
 * `int48 + int64 -> int64` and `int64` and there cannot be a smaller solution.
 *
 * //TODO: Maybe this function should allow not setting an error?
 *
 * @param length Number of dtypes (and values) must be at least 1
 * @param dtypes The concrete or abstract DTypes to promote
 * @return NULL or the promoted DType.
 */
NPY_NO_EXPORT PyArray_DTypeMeta *
PyArray_PromoteDTypeSequence(
        npy_intp length, PyArray_DTypeMeta **dtypes_in)
{
    // 如果只有一个dtype,直接返回该dtype,增加其引用计数
    if (length == 1) {
        Py_INCREF(dtypes_in[0]);
        return dtypes_in[0];
    }
    
    // 否则初始化结果为NULL
    PyArray_DTypeMeta *result = NULL;

    /* Copy dtypes so that we can reorder them (only allocate when many) */
    // 使用栈上的数组或堆上的数组来复制dtypes,以便重新排序(只有在长度大时才分配堆上内存)
    PyObject *_scratch_stack[NPY_MAXARGS];
    PyObject **_scratch_heap = NULL;
    PyArray_DTypeMeta **dtypes = (PyArray_DTypeMeta **)_scratch_stack;
    # 如果传入的长度超过了预定义的最大参数个数 NPY_MAXARGS,则分配一个临时内存空间 _scratch_heap 来存储 PyObject 指针数组
    if (length > NPY_MAXARGS) {
        _scratch_heap = PyMem_Malloc(length * sizeof(PyObject *));
        // 如果分配内存失败,则设置内存错误并返回 NULL
        if (_scratch_heap == NULL) {
            PyErr_NoMemory();
            return NULL;
        }
        // 将 _scratch_heap 强制转换为 PyArray_DTypeMeta 指针数组,用于存储传入的 dtypes
        dtypes = (PyArray_DTypeMeta **)_scratch_heap;
    }

    // 将 dtypes_in 数组中的数据拷贝到 dtypes 数组中,拷贝的字节数为 length * sizeof(PyObject *)
    memcpy(dtypes, dtypes_in, length * sizeof(PyObject *));

    /*
     * `result` 是最后的推广结果,通常情况下可以重复使用,除非它是 NotImplemneted。
     * 传入的 dtypes 已部分排序,并在不再相关时已清除。
     * `dtypes[0]` 将是最有知识(最高类别)的 dtype,这里我们称之为 "main_dtype"。
     */
    // 调用 reduce_dtypes_to_most_knowledgeable 函数处理 dtypes,返回推广后的结果给 result
    result = reduce_dtypes_to_most_knowledgeable(length, dtypes);
    // 如果 result 为 NULL,则跳转至 finish 标签处
    if (result == NULL) {
        goto finish;
    }
    // 将 dtypes[0] 赋值给 main_dtype,表示最有知识的 dtype
    PyArray_DTypeMeta *main_dtype = dtypes[0];

    // reduce_start 初始化为 1
    npy_intp reduce_start = 1;
    // 如果 result 是 Py_NotImplemented,则将 result 设置为 NULL
    if (result == (PyArray_DTypeMeta *)Py_NotImplemented) {
        Py_SETREF(result, NULL);
    }
    else {
        /* (new) first value is already taken care of in `result` */
        // 否则,reduce_start 设置为 2,表示处理的起始位置
        reduce_start = 2;
    }
    /*
     * 到此为止,我们最多只查看了每个 DType 一次。
     * `main_dtype` 必须了解所有其他 dtype(否则将会失败),
     * 并且其 `common_dtype` 返回的所有 dtype 必须保证能够互相推广成功。
     * 在这一点上,"main DType" 的任务是确保顺序无关紧要。
     * 如果这证明是一个限制,这种 "reduction" 将必须变成一个默认版本,并允许 DType 来覆盖它。
     */
    // prev 初始化为 NULL
    PyArray_DTypeMeta *prev = NULL;
   `
    for (npy_intp i = reduce_start; i < length; i++) {
        // 循环遍历从 reduce_start 开始的 dtypes 数组
        if (dtypes[i] == NULL || dtypes[i] == prev) {
            // 如果当前 dtypes[i] 是 NULL 或者与前一个相同,则跳过当前循环
            continue;
        }
        /*
         * 将当前 dtype 与主 dtype 进行"提升"(promotion),假设结果不会低于主 dtype 的类别。
         */
        PyArray_DTypeMeta *promotion = NPY_DT_CALL_common_dtype(
                main_dtype, dtypes[i]);
        if (promotion == NULL) {
            // 如果提升失败,则设置 result 为 NULL,并跳转至 finish 标签处
            Py_XSETREF(result, NULL);
            goto finish;
        }
        else if ((PyObject *)promotion == Py_NotImplemented) {
            // 如果提升操作返回 Py_NotImplemented,则处理错误情况
            Py_DECREF(Py_NotImplemented);
            Py_XSETREF(result, NULL);
            PyObject *dtypes_in_tuple = PyTuple_New(length);
            if (dtypes_in_tuple == NULL) {
                goto finish;
            }
            // 构建一个包含所有 dtypes 的元组
            for (npy_intp l=0; l < length; l++) {
                Py_INCREF(dtypes_in[l]);
                PyTuple_SET_ITEM(dtypes_in_tuple, l, (PyObject *)dtypes_in[l]);
            }
            // 设置错误信息并跳转至 finish 标签处
            PyErr_Format(npy_static_pydata.DTypePromotionError,
                    "The DType %S could not be promoted by %S. This means that "
                    "no common DType exists for the given inputs. "
                    "For example they cannot be stored in a single array unless "
                    "the dtype is `object`. The full list of DTypes is: %S",
                    dtypes[i], main_dtype, dtypes_in_tuple);
            Py_DECREF(dtypes_in_tuple);
            goto finish;
        }
        if (result == NULL) {
            // 如果 result 为 NULL,则将其设置为当前的 promotion
            result = promotion;
            continue;
        }

        /*
         * 以上步骤完成提升后,现在与当前的 result 进行"减少"(reduce)操作;
         * 注意在典型情况下,我们预期这一步骤不会产生实际操作。
         */
        Py_SETREF(result, PyArray_CommonDType(result, promotion));
        Py_DECREF(promotion);
        if (result == NULL) {
            // 如果操作后 result 为 NULL,则跳转至 finish 标签处
            goto finish;
        }
    }

  finish:
    // 释放临时内存
    PyMem_Free(_scratch_heap);
    // 返回最终的 result
    return result;
}



# 这是一个单独的右大括号 '}',通常用于结束一个代码块或者数据结构的定义。

.\numpy\numpy\_core\src\multiarray\compiled_base.c

/*
 * 定义 NPY_NO_DEPRECATED_API 为 NPY_API_VERSION,避免使用已弃用的 API
 * 定义 _MULTIARRAYMODULE
 */
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
#define _MULTIARRAYMODULE

/*
 * 引入必要的头文件:
 * - Python.h:Python C API 的核心头文件
 * - structmember.h:定义结构体成员的相关宏和函数
 * - arrayobject.h:NumPy 多维数组对象的头文件
 * - npy_3kcompat.h:NumPy 兼容 Python 3 的头文件
 * - npy_math.h:NumPy 数学运算的头文件
 * - npy_argparse.h:NumPy 参数解析相关的头文件
 * - npy_config.h:NumPy 的配置文件
 * - templ_common.h:用于模板通用操作的头文件,如 npy_mul_sizes_with_overflow
 * - lowlevel_strided_loops.h:低级别分块循环的头文件,如 npy_bswap8
 * - alloc.h:内存分配相关的头文件
 * - ctors.h:构造函数相关的头文件
 * - common.h:通用工具函数的头文件
 * - dtypemeta.h:数据类型元信息的头文件
 * - simd/simd.h:SIMD(单指令多数据)操作的头文件
 * - string.h:C 标准字符串操作的头文件
 */
#include <Python.h>
#include <structmember.h>
#include "numpy/arrayobject.h"
#include "numpy/npy_3kcompat.h"
#include "numpy/npy_math.h"
#include "npy_argparse.h"
#include "npy_config.h"
#include "templ_common.h" /* for npy_mul_sizes_with_overflow */
#include "lowlevel_strided_loops.h" /* for npy_bswap8 */
#include "alloc.h"
#include "ctors.h"
#include "common.h"
#include "dtypemeta.h"
#include "simd/simd.h"
#include <string.h>

/*
 * 定义枚举 PACK_ORDER,用于表示打包顺序:
 * - PACK_ORDER_LITTLE:小端顺序
 * - PACK_ORDER_BIG:大端顺序
 */
typedef enum {
    PACK_ORDER_LITTLE = 0,
    PACK_ORDER_BIG
} PACK_ORDER;

/*
 * 检查数组是否单调的函数
 * 返回值:
 * -1:数组单调递减
 * +1:数组单调递增
 *  0:数组不单调
 */
static int
check_array_monotonic(const double *a, npy_intp lena)
{
    npy_intp i;
    double next;
    double last;

    if (lena == 0) {
        /* 如果数组长度为0,所有的元素都相同,认为是单调递增 */
        return 1;
    }
    last = a[0];

    /* 跳过数组开头的重复值 */
    for (i = 1; (i < lena) && (a[i] == last); i++);

    if (i == lena) {
        /* 如果跳过重复值后数组长度为0,所有的元素都相同,认为是单调递增 */
        return 1;
    }

    next = a[i];
    if (last < next) {
        /* 可能是单调递增 */
        for (i += 1; i < lena; i++) {
            last = next;
            next = a[i];
            if (last > next) {
                return 0;
            }
        }
        return 1;
    }
    else {
        /* last > next,可能是单调递减 */
        for (i += 1; i < lena; i++) {
            last = next;
            next = a[i];
            if (last < next) {
                return 0;
            }
        }
        return -1;
    }
}

/*
 * 找到整数数组的最小值和最大值的函数
 */
static void
minmax(const npy_intp *data, npy_intp data_len, npy_intp *mn, npy_intp *mx)
{
    npy_intp min = *data;
    npy_intp max = *data;

    while (--data_len) {
        const npy_intp val = *(++data);
        if (val < min) {
            min = val;
        }
        else if (val > max) {
            max = val;
        }
    }

    *mn = min;
    *mx = max;
}

/*
 * 注册为 bincount 的 arr_bincount 函数
 * bincount 接受一个、两个或三个参数:
 * - 第一个参数是非负整数数组
 * - 第二个参数是权重数组(如果有),必须能够提升为 double 类型
 * - 第三个参数(如果有)是期望输出数组的最小长度
 * 如果没有权重数组,bincount(list)[i] 表示在 list 中出现 i 的次数;
 * 如果有权重数组,则 bincount(self, list, weight)[i] 表示所有 list[j] == i 的权重和。
 * 不使用 Self 参数。
 */
NPY_NO_EXPORT PyObject *
arr_bincount(PyObject *NPY_UNUSED(self), PyObject *const *args,
                            Py_ssize_t len_args, PyObject *kwnames)
{
    // 声明变量,用于存储函数参数和结果
    PyObject *list = NULL, *weight = Py_None, *mlength = NULL;
    PyArrayObject *lst = NULL, *ans = NULL, *wts = NULL;
    npy_intp *numbers, *ians, len, mx, mn, ans_size;
    npy_intp minlength = 0;
    npy_intp i;
    double *weights , *dans;

    // 解析函数参数
    NPY_PREPARE_ARGPARSER;
    if (npy_parse_arguments("bincount", args, len_args, kwnames,
                "list", NULL, &list,
                "|weights", NULL, &weight,
                "|minlength", NULL, &mlength,
                NULL, NULL, NULL) < 0) {
        return NULL;
    }

    // 将传入的列表参数转换为一维整型数组对象
    lst = (PyArrayObject *)PyArray_ContiguousFromAny(list, NPY_INTP, 1, 1);
    if (lst == NULL) {
        goto fail;
    }
    len = PyArray_SIZE(lst);

    /*
     * This if/else if can be removed by changing the argspec to O|On above,
     * once we retire the deprecation
     */
    // 处理 minlength 参数的特殊情况
    if (mlength == Py_None) {
        /* NumPy 1.14, 2017-06-01 */
        // 发出弃用警告,建议传入 0 作为 minlength 而不是 None
        if (DEPRECATE("0 should be passed as minlength instead of None; "
                      "this will error in future.") < 0) {
            goto fail;
        }
    }
    else if (mlength != NULL) {
        // 将传入的 minlength 参数转换为 npy_intp 类型
        minlength = PyArray_PyIntAsIntp(mlength);
        if (error_converting(minlength)) {
            goto fail;
        }
    }

    // 检查 minlength 是否为负数,若是则报错并跳转到错误处理部分
    if (minlength < 0) {
        PyErr_SetString(PyExc_ValueError,
                        "'minlength' must not be negative");
        goto fail;
    }

    // 处理空列表的情况
    if (len == 0) {
        // 创建一个长度为 minlength 的全零数组对象
        ans = (PyArrayObject *)PyArray_ZEROS(1, &minlength, NPY_INTP, 0);
        if (ans == NULL){
            goto fail;
        }
        // 释放 lst 对象,并返回结果数组对象
        Py_DECREF(lst);
        return (PyObject *)ans;
    }

    // 获取列表数据的指针,并计算列表中的最小值和最大值
    numbers = (npy_intp *)PyArray_DATA(lst);
    minmax(numbers, len, &mn, &mx);
    // 检查列表中是否有负数,若有则报错并跳转到错误处理部分
    if (mn < 0) {
        PyErr_SetString(PyExc_ValueError,
                "'list' argument must have no negative elements");
        goto fail;
    }
    // 计算结果数组的大小
    ans_size = mx + 1;
    // 如果传入了 minlength 参数且 ans_size 小于 minlength,则以 minlength 为准
    if (mlength != Py_None) {
        if (ans_size < minlength) {
            ans_size = minlength;
        }
    }
    // 处理未传入权重参数的情况
    if (weight == Py_None) {
        // 创建一个长度为 ans_size 的全零数组对象
        ans = (PyArrayObject *)PyArray_ZEROS(1, &ans_size, NPY_INTP, 0);
        if (ans == NULL) {
            goto fail;
        }
        // 获取结果数组的数据指针,开启线程,并根据列表中的元素值进行计数
        ians = (npy_intp *)PyArray_DATA(ans);
        NPY_BEGIN_ALLOW_THREADS;
        for (i = 0; i < len; i++)
            ians[numbers[i]] += 1;
        NPY_END_ALLOW_THREADS;
        // 释放 lst 对象
        Py_DECREF(lst);
    }
    // 如果不是首次调用该函数,则执行以下操作
    else {
        // 从给定对象 `weight` 创建一个连续的 `PyArrayObject` 对象,数据类型为双精度浮点数
        wts = (PyArrayObject *)PyArray_ContiguousFromAny(
                                                weight, NPY_DOUBLE, 1, 1);
        // 如果 `wts` 为 NULL,则跳转到失败处理标签
        if (wts == NULL) {
            goto fail;
        }
        // 获取 `wts` 对象的数据指针,并赋给 `weights`
        weights = (double *)PyArray_DATA(wts);
        // 如果 `wts` 对象的大小与 `len` 不相等,则设置错误信息并跳转到失败处理标签
        if (PyArray_SIZE(wts) != len) {
            PyErr_SetString(PyExc_ValueError,
                    "The weights and list don't have the same length.");
            goto fail;
        }
        // 创建一个元素个数为 `ans_size` 的双精度浮点数类型的零数组 `ans`
        ans = (PyArrayObject *)PyArray_ZEROS(1, &ans_size, NPY_DOUBLE, 0);
        // 如果 `ans` 为 NULL,则跳转到失败处理标签
        if (ans == NULL) {
            goto fail;
        }
        // 获取 `ans` 对象的数据指针,并赋给 `dans`
        dans = (double *)PyArray_DATA(ans);
        // 开始线程允许,用于多线程环境下的线程安全操作
        NPY_BEGIN_ALLOW_THREADS;
        // 遍历长度为 `len` 的循环
        for (i = 0; i < len; i++) {
            // 将 `weights[i]` 的值加到 `dans[numbers[i]]` 上
            dans[numbers[i]] += weights[i];
        }
        // 结束线程允许,恢复线程锁状态
        NPY_END_ALLOW_THREADS;
        // 释放 `lst` 和 `wts` 对象的引用
        Py_DECREF(lst);
        Py_DECREF(wts);
    }
    // 返回 `ans` 对象的 PyObject 指针形式
    return (PyObject *)ans;
fail:
    // 释放 lst 对象的引用计数
    Py_XDECREF(lst);
    // 释放 wts 对象的引用计数
    Py_XDECREF(wts);
    // 释放 ans 对象的引用计数
    Py_XDECREF(ans);
    // 返回 NULL 表示函数执行失败
    return NULL;
}

/* Internal function to expose check_array_monotonic to python */
// 定义一个不导出的函数,将 check_array_monotonic 暴露给 Python
NPY_NO_EXPORT PyObject *
arr__monotonicity(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwds)
{
    static char *kwlist[] = {"x", NULL};
    PyObject *obj_x = NULL;
    PyArrayObject *arr_x = NULL;
    long monotonic;
    npy_intp len_x;
    NPY_BEGIN_THREADS_DEF;

    // 解析参数,期望参数是一个对象和一个关键字参数列表
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:_monotonicity", kwlist,
                                     &obj_x)) {
        // 解析失败,返回 NULL
        return NULL;
    }

    /*
     * TODO:
     *  `x` could be strided, needs change to check_array_monotonic
     *  `x` is forced to double for this check
     */
    // 将 obj_x 转换为一个一维的 NPY_DOUBLE 类型的 PyArrayObject,以供后续的单调性检查使用
    arr_x = (PyArrayObject *)PyArray_FROMANY(
        obj_x, NPY_DOUBLE, 1, 1, NPY_ARRAY_CARRAY_RO);
    if (arr_x == NULL) {
        // 转换失败,返回 NULL
        return NULL;
    }

    len_x = PyArray_SIZE(arr_x);  // 获取数组 arr_x 的大小
    NPY_BEGIN_THREADS_THRESHOLDED(len_x)
    monotonic = check_array_monotonic(
        (const double *)PyArray_DATA(arr_x), len_x);  // 调用 check_array_monotonic 函数进行单调性检查
    NPY_END_THREADS
    Py_DECREF(arr_x);  // 释放 arr_x 对象的引用计数

    // 将检查结果 monotonic 转换为 Python 的 long 类型,并返回
    return PyLong_FromLong(monotonic);
}

/*
 * Returns input array with values inserted sequentially into places
 * indicated by the mask
 */
// 返回一个在 mask 指示的位置上顺序插入值的输入数组
NPY_NO_EXPORT PyObject *
arr_place(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwdict)
{
    char *src, *dest;
    npy_bool *mask_data;
    PyArray_Descr *dtype;
    PyArray_CopySwapFunc *copyswap;
    PyObject *array0, *mask0, *values0;
    PyArrayObject *array, *mask, *values;
    npy_intp i, j, chunk, nm, ni, nv;

    static char *kwlist[] = {"input", "mask", "vals", NULL};
    NPY_BEGIN_THREADS_DEF;
    values = mask = NULL;

    // 解析参数,期望参数是一个 PyArray_Type 类型的对象,以及两个任意对象
    if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O!OO:place", kwlist,
                &PyArray_Type, &array0, &mask0, &values0)) {
        // 解析失败,返回 NULL
        return NULL;
    }

    // 将 array0 转换为一个 NPY_ARRAY_CARRAY | NPY_ARRAY_WRITEBACKIFCOPY 类型的 PyArrayObject 对象
    array = (PyArrayObject *)PyArray_FromArray((PyArrayObject *)array0, NULL,
                                    NPY_ARRAY_CARRAY | NPY_ARRAY_WRITEBACKIFCOPY);
    if (array == NULL) {
        goto fail;  // 转换失败,跳转到 fail 标签处理异常
    }

    ni = PyArray_SIZE(array);  // 获取数组 array 的大小
    dest = PyArray_DATA(array);  // 获取数组 array 的数据起始地址
    chunk = PyArray_ITEMSIZE(array);  // 获取数组 array 的每个元素大小
    // 将 mask0 转换为一个 NPY_BOOL 类型的 PyArrayObject 对象
    mask = (PyArrayObject *)PyArray_FROM_OTF(mask0, NPY_BOOL,
                                NPY_ARRAY_CARRAY | NPY_ARRAY_FORCECAST);
    if (mask == NULL) {
        goto fail;  // 转换失败,跳转到 fail 标签处理异常
    }

    nm = PyArray_SIZE(mask);  // 获取数组 mask 的大小
    if (nm != ni) {
        // mask 和 array 大小不匹配,抛出 ValueError 异常
        PyErr_SetString(PyExc_ValueError,
                        "place: mask and data must be "
                        "the same size");
        goto fail;  // 跳转到 fail 标签处理异常
    }

    mask_data = PyArray_DATA(mask);  // 获取数组 mask 的数据起始地址
    dtype = PyArray_DESCR(array);  // 获取数组 array 的数据描述符
    Py_INCREF(dtype);  // 增加数据描述符的引用计数

    // 将 values0 转换为一个 NPY_ARRAY_CARRAY 类型的 PyArrayObject 对象
    values = (PyArrayObject *)PyArray_FromAny(values0, dtype,
                                    0, 0, NPY_ARRAY_CARRAY, NULL);
    if (values == NULL) {
        goto fail;  // 转换失败,跳转到 fail 标签处理异常
    }

    nv = PyArray_SIZE(values);  // 获取数组 values 的大小(如果是空数组,则为零)
    # 检查插入值数量是否小于等于零
    if (nv <= 0):
        # 初始化一个布尔变量,用于标记所有值是否都为假
        npy_bool allFalse = 1;
        i = 0;

        # 遍历掩码数据,查找是否存在非零值
        while (allFalse && i < ni):
            if (mask_data[i]):
                allFalse = 0;
            else:
                i++;

        # 如果存在非零值,则抛出值错误异常
        if (!allFalse):
            PyErr_SetString(PyExc_ValueError,
                            "Cannot insert from an empty array!");
            # 跳转到错误处理标签
            goto fail;
        else:
            # 清理内存并返回 None
            Py_XDECREF(values);
            Py_XDECREF(mask);
            PyArray_ResolveWritebackIfCopy(array);
            Py_XDECREF(array);
            Py_RETURN_NONE;

    # 获取源数据的指针
    src = PyArray_DATA(values);
    j = 0;

    # 获取目标数组元素的复制交换函数
    copyswap = PyDataType_GetArrFuncs(PyArray_DESCR(array))->copyswap;
    # 启动线程(如果支持)
    NPY_BEGIN_THREADS_DESCR(PyArray_DESCR(array));
    # 遍历输入数据
    for (i = 0; i < ni; i++) {
        if (mask_data[i]):
            # 确保复制的索引不超出目标数组的长度
            if (j >= nv):
                j = 0;

            # 执行复制交换操作
            copyswap(dest + i*chunk, src + j*chunk, 0, array);
            j++;
    }
    # 结束线程
    NPY_END_THREADS;

    # 清理内存并返回 None
    Py_XDECREF(values);
    Py_XDECREF(mask);
    PyArray_ResolveWritebackIfCopy(array);
    Py_DECREF(array);
    Py_RETURN_NONE;

fail:
    # 清理内存并返回 NULL,表示失败
    Py_XDECREF(mask);
    PyArray_ResolveWritebackIfCopy(array);
    Py_XDECREF(array);
    Py_XDECREF(values);
    return NULL;
}

#define LIKELY_IN_CACHE_SIZE 8

#ifdef __INTEL_COMPILER
#pragma intel optimization_level 0
#endif

/**
 * @brief Perform a linear search in a sorted array to find the largest index
 * such that the array element is less than or equal to the given key.
 *
 * @param key Key value to search for.
 * @param arr Sorted array to search within.
 * @param len Length of the array.
 * @param i0 Starting index for the search.
 * @return Largest index i such that arr[i] <= key.
 */
static inline npy_intp
_linear_search(const npy_double key, const npy_double *arr, const npy_intp len, const npy_intp i0)
{
    npy_intp i;

    for (i = i0; i < len && key >= arr[i]; i++);
    return i - 1;
}

/**
 * @brief Perform a binary search in a sorted array to find the index such that
 * arr[i] <= key < arr[i + 1].
 *
 * If a starting index guess is provided, it checks nearby values first.
 * Otherwise, it defaults to bisection method for finding the index.
 *
 * @param key Key value to search for.
 * @param arr Sorted array to search within.
 * @param len Length of the array.
 * @param guess Initial guess for the index.
 * @return Index i such that arr[i] <= key < arr[i + 1].
 */
static npy_intp
binary_search_with_guess(const npy_double key, const npy_double *arr,
                         npy_intp len, npy_intp guess)
{
    npy_intp imin = 0;
    npy_intp imax = len;

    /* Handle keys outside of the arr range first */
    if (key > arr[len - 1]) {
        return len;
    }
    else if (key < arr[0]) {
        return -1;
    }

    /*
     * If len <= 4 use linear search.
     * From above we know key >= arr[0] when we start.
     */
    if (len <= 4) {
        return _linear_search(key, arr, len, 1);
    }

    if (guess > len - 3) {
        guess = len - 3;
    }
    if (guess < 1)  {
        guess = 1;
    }

    /* check most likely values: guess - 1, guess, guess + 1 */
    if (key < arr[guess]) {
        if (key < arr[guess - 1]) {
            imax = guess - 1;
            /* last attempt to restrict search to items in cache */
            if (guess > LIKELY_IN_CACHE_SIZE &&
                        key >= arr[guess - LIKELY_IN_CACHE_SIZE]) {
                imin = guess - LIKELY_IN_CACHE_SIZE;
            }
        }
        else {
            /* key >= arr[guess - 1] */
            return guess - 1;
        }
    }
    else {
        /* key >= arr[guess] */
        if (key < arr[guess + 1]) {
            return guess;
        }
        else {
            /* key >= arr[guess + 1] */
            if (key < arr[guess + 2]) {
                return guess + 1;
            }
            else {
                /* key >= arr[guess + 2] */
                imin = guess + 2;
                /* last attempt to restrict search to items in cache */
                if (guess < len - LIKELY_IN_CACHE_SIZE - 1 &&
                            key < arr[guess + LIKELY_IN_CACHE_SIZE]) {
                    imax = guess + LIKELY_IN_CACHE_SIZE;
                }
            }
        }
    }

    /* finally, find index by bisection */
    # 当最小索引小于最大索引时,执行循环
    while (imin < imax) {
        # 计算中间索引,避免溢出风险
        const npy_intp imid = imin + ((imax - imin) >> 1);
        # 如果目标值大于等于中间元素,调整最小索引到中间索引的下一个位置
        if (key >= arr[imid]) {
            imin = imid + 1;
        }
        # 否则,调整最大索引到中间索引处
        else {
            imax = imid;
        }
    }
    # 返回找到的目标值的位置,因为可能出现key小于arr[0]的情况,所以返回imin-1
    return imin - 1;
    }

#undef LIKELY_IN_CACHE_SIZE

NPY_NO_EXPORT PyObject *
arr_interp(PyObject *NPY_UNUSED(self), PyObject *const *args, Py_ssize_t len_args,
                             PyObject *kwnames)
{
    // 指针声明
    PyObject *fp, *xp, *x;
    // 左右边界初始化为 NULL
    PyObject *left = NULL, *right = NULL;
    // 数组对象声明
    PyArrayObject *afp = NULL, *axp = NULL, *ax = NULL, *af = NULL;
    // 索引变量声明
    npy_intp i, lenx, lenxp;
    // 左右边界值声明
    npy_double lval, rval;
    // 指向数据的指针声明
    const npy_double *dy, *dx, *dz;
    npy_double *dres, *slopes = NULL;

    // 线程操作宏定义
    NPY_BEGIN_THREADS_DEF;

    // 参数解析准备
    NPY_PREPARE_ARGPARSER;
    // 解析函数参数,如果失败返回 NULL
    if (npy_parse_arguments("interp", args, len_args, kwnames,
                "x", NULL, &x,
                "xp", NULL, &xp,
                "fp", NULL, &fp,
                "|left", NULL, &left,
                "|right", NULL, &right,
                NULL, NULL, NULL) < 0) {
        return NULL;
    }

    // 将 fp 转换为 NPY_DOUBLE 类型的连续数组对象
    afp = (PyArrayObject *)PyArray_ContiguousFromAny(fp, NPY_DOUBLE, 1, 1);
    if (afp == NULL) {
        return NULL;
    }
    // 将 xp 转换为 NPY_DOUBLE 类型的连续数组对象
    axp = (PyArrayObject *)PyArray_ContiguousFromAny(xp, NPY_DOUBLE, 1, 1);
    if (axp == NULL) {
        goto fail;
    }
    // 将 x 转换为 NPY_DOUBLE 类型的数组对象
    ax = (PyArrayObject *)PyArray_ContiguousFromAny(x, NPY_DOUBLE, 0, 0);
    if (ax == NULL) {
        goto fail;
    }
    // 获取 axp 的长度
    lenxp = PyArray_SIZE(axp);
    // 如果长度为 0,抛出异常并跳转到失败处理标签
    if (lenxp == 0) {
        PyErr_SetString(PyExc_ValueError,
                "array of sample points is empty");
        goto fail;
    }
    // 检查 afp 和 axp 的长度是否相同,如果不同则抛出异常并跳转到失败处理标签
    if (PyArray_SIZE(afp) != lenxp) {
        PyErr_SetString(PyExc_ValueError,
                "fp and xp are not of the same length.");
        goto fail;
    }

    // 创建一个与 ax 具有相同维度和形状的 NPY_DOUBLE 类型的新数组对象 af
    af = (PyArrayObject *)PyArray_SimpleNew(PyArray_NDIM(ax),
                                            PyArray_DIMS(ax), NPY_DOUBLE);
    if (af == NULL) {
        goto fail;
    }
    // 获取 ax 的长度
    lenx = PyArray_SIZE(ax);

    // 获取 afp、axp、ax、af 数组对象的数据指针
    dy = (const npy_double *)PyArray_DATA(afp);
    dx = (const npy_double *)PyArray_DATA(axp);
    dz = (const npy_double *)PyArray_DATA(ax);
    dres = (npy_double *)PyArray_DATA(af);
    /* 获取左右填充值。*/
    if ((left == NULL) || (left == Py_None)) {
        lval = dy[0];
    }
    else {
        lval = PyFloat_AsDouble(left);
        // 如果转换失败则跳转到失败处理标签
        if (error_converting(lval)) {
            goto fail;
        }
    }
    if ((right == NULL) || (right == Py_None)) {
        rval = dy[lenxp - 1];
    }
    else {
        rval = PyFloat_AsDouble(right);
        // 如果转换失败则跳转到失败处理标签
        if (error_converting(rval)) {
            goto fail;
        }
    }

    /* binary_search_with_guess 至少需要一个长度为 3 的数组 */
    if (lenxp == 1) {
        const npy_double xp_val = dx[0];
        const npy_double fp_val = dy[0];

        // 多线程处理,根据 lenx 的大小决定是否启动多线程
        NPY_BEGIN_THREADS_THRESHOLDED(lenx);
        // 对于每个 x 中的元素进行插值计算
        for (i = 0; i < lenx; ++i) {
            const npy_double x_val = dz[i];
            dres[i] = (x_val < xp_val) ? lval :
                                         ((x_val > xp_val) ? rval : fp_val);
        }
        // 结束多线程处理
        NPY_END_THREADS;
    }
    else {
        npy_intp j = 0;

        /* only pre-calculate slopes if there are relatively few of them. */
        如果斜率相对较少,则预先计算斜率
        if (lenxp <= lenx) {
            // 分配内存以存储斜率数组,长度为 (lenxp - 1)
            slopes = PyArray_malloc((lenxp - 1) * sizeof(npy_double));
            // 如果分配失败,报告内存错误并跳转到失败处理部分
            if (slopes == NULL) {
                PyErr_NoMemory();
                goto fail;
            }
        }

        NPY_BEGIN_THREADS;  // 开始线程安全区域

        // 如果斜率数组非空,计算每段斜率
        if (slopes != NULL) {
            for (i = 0; i < lenxp - 1; ++i) {
                slopes[i] = (dy[i+1] - dy[i]) / (dx[i+1] - dx[i]);
            }
        }

        // 对每个需要插值的点进行处理
        for (i = 0; i < lenx; ++i) {
            const npy_double x_val = dz[i];

            // 如果 x_val 是 NaN,直接将结果设为 x_val 并继续下一个点
            if (npy_isnan(x_val)) {
                dres[i] = x_val;
                continue;
            }

            // 使用二分查找找到 x_val 在 dx 中的位置,j 是初始猜测位置
            j = binary_search_with_guess(x_val, dx, lenxp, j);

            // 根据查找结果决定如何插值
            if (j == -1) {
                dres[i] = lval;  // 如果找不到合适位置,结果设为左边界值 lval
            }
            else if (j == lenxp) {
                dres[i] = rval;  // 如果超出右边界,结果设为右边界值 rval
            }
            else if (j == lenxp - 1) {
                dres[i] = dy[j];  // 如果在最后一个点上,结果直接设为对应的 dy 值
            }
            else if (dx[j] == x_val) {
                /* Avoid potential non-finite interpolation */
                // 如果精确找到了点,避免潜在的非有限插值问题,结果直接设为对应的 dy 值
                dres[i] = dy[j];
            }
            else {
                const npy_double slope =
                        (slopes != NULL) ? slopes[j] :
                        (dy[j+1] - dy[j]) / (dx[j+1] - dx[j]);

                // 使用线性插值计算结果
                dres[i] = slope*(x_val - dx[j]) + dy[j];

                // 如果插值结果是 NaN,尝试使用相邻点进行插值
                if (NPY_UNLIKELY(npy_isnan(dres[i]))) {
                    dres[i] = slope*(x_val - dx[j+1]) + dy[j+1];

                    // 如果再次插值结果仍然是 NaN,并且相邻点的 dy 值相同,则结果设为相邻点的 dy 值
                    if (NPY_UNLIKELY(npy_isnan(dres[i])) && dy[j] == dy[j+1]) {
                        dres[i] = dy[j];
                    }
                }
            }
        }

        NPY_END_THREADS;  // 结束线程安全区域
    }

    // 释放斜率数组内存
    PyArray_free(slopes);

    // 释放引用的数组对象
    Py_DECREF(afp);
    Py_DECREF(axp);
    Py_DECREF(ax);

    // 返回插值结果数组对象
    return PyArray_Return(af);
fail:
    // 释放 afp 指针所指向的对象,并将其引用计数减少,避免内存泄漏
    Py_XDECREF(afp);
    // 释放 axp 指针所指向的对象,并将其引用计数减少,避免内存泄漏
    Py_XDECREF(axp);
    // 释放 ax 指针所指向的对象,并将其引用计数减少,避免内存泄漏
    Py_XDECREF(ax);
    // 释放 af 指针所指向的对象,并将其引用计数减少,避免内存泄漏
    Py_XDECREF(af);
    // 返回 NULL 表示函数执行失败
    return NULL;
}

/* As for arr_interp but for complex fp values */
NPY_NO_EXPORT PyObject *
arr_interp_complex(PyObject *NPY_UNUSED(self), PyObject *const *args, Py_ssize_t len_args,
                             PyObject *kwnames)
{
    // 声明需要使用的变量
    PyObject *fp, *xp, *x;
    PyObject *left = NULL, *right = NULL;
    PyArrayObject *afp = NULL, *axp = NULL, *ax = NULL, *af = NULL;
    npy_intp i, lenx, lenxp;

    const npy_double *dx, *dz;
    const npy_cdouble *dy;
    npy_cdouble lval, rval;
    npy_cdouble *dres, *slopes = NULL;

    NPY_BEGIN_THREADS_DEF;

    // 准备解析参数
    NPY_PREPARE_ARGPARSER;
    if (npy_parse_arguments("interp_complex", args, len_args, kwnames,
                "x", NULL, &x,
                "xp", NULL, &xp,
                "fp", NULL, &fp,
                "|left", NULL, &left,
                "|right", NULL, &right,
                NULL, NULL, NULL) < 0) {
        // 解析参数失败,返回 NULL 表示函数执行失败
        return NULL;
    }

    // 将 fp 转换为 NPY_CDOUBLE 类型的连续数组对象
    afp = (PyArrayObject *)PyArray_ContiguousFromAny(fp, NPY_CDOUBLE, 1, 1);

    if (afp == NULL) {
        // 转换失败,返回 NULL 表示函数执行失败
        return NULL;
    }

    // 将 xp 转换为 NPY_DOUBLE 类型的连续数组对象
    axp = (PyArrayObject *)PyArray_ContiguousFromAny(xp, NPY_DOUBLE, 1, 1);
    if (axp == NULL) {
        // 转换失败,跳转到 fail 标签处处理错误
        goto fail;
    }
    // 将 x 转换为 NPY_DOUBLE 类型的连续数组对象
    ax = (PyArrayObject *)PyArray_ContiguousFromAny(x, NPY_DOUBLE, 0, 0);
    if (ax == NULL) {
        // 转换失败,跳转到 fail 标签处处理错误
        goto fail;
    }
    lenxp = PyArray_SIZE(axp);
    if (lenxp == 0) {
        // xp 数组长度为 0,抛出 ValueError 异常并跳转到 fail 标签处处理错误
        PyErr_SetString(PyExc_ValueError,
                "array of sample points is empty");
        goto fail;
    }
    if (PyArray_SIZE(afp) != lenxp) {
        // fp 和 xp 数组长度不相等,抛出 ValueError 异常并跳转到 fail 标签处处理错误
        PyErr_SetString(PyExc_ValueError,
                "fp and xp are not of the same length.");
        goto fail;
    }

    lenx = PyArray_SIZE(ax);
    dx = (const npy_double *)PyArray_DATA(axp);
    dz = (const npy_double *)PyArray_DATA(ax);

    // 创建一个新的 NPY_CDOUBLE 类型的数组对象 af
    af = (PyArrayObject *)PyArray_SimpleNew(PyArray_NDIM(ax),
                                            PyArray_DIMS(ax), NPY_CDOUBLE);
    if (af == NULL) {
        // 创建失败,跳转到 fail 标签处处理错误
        goto fail;
    }

    dy = (const npy_cdouble *)PyArray_DATA(afp);
    dres = (npy_cdouble *)PyArray_DATA(af);
    /* 获取 left 和 right 填充值 */
    if ((left == NULL) || (left == Py_None)) {
        // 如果 left 为 NULL 或者 Py_None,则将 lval 设置为 dy[0]
        lval = dy[0];
    }
    else {
        // 否则,从 left 中获取实部和虚部,并进行类型转换,如果转换失败则跳转到 fail 标签处理错误
        npy_csetreal(&lval, PyComplex_RealAsDouble(left));
        if (error_converting(npy_creal(lval))) {
            goto fail;
        }
        npy_csetimag(&lval, PyComplex_ImagAsDouble(left));
        if (error_converting(npy_cimag(lval))) {
            goto fail;
        }
    }

    if ((right == NULL) || (right == Py_None)) {
        // 如果 right 为 NULL 或者 Py_None,则将 rval 设置为 dy[lenxp - 1]
        rval = dy[lenxp - 1];
    }
    else {
        // 否则,从 right 中获取实部和虚部,并进行类型转换,如果转换失败则跳转到 fail 标签处理错误
        npy_csetreal(&rval, PyComplex_RealAsDouble(right));
        if (error_converting(npy_creal(rval))) {
            goto fail;
        }
        npy_csetimag(&rval, PyComplex_ImagAsDouble(right));
        if (error_converting(npy_cimag(rval))) {
            goto fail;
        }
    }

    // binary_search_with_guess 需要至少一个包含 3 个元素的数组
    # 如果 lenxp 等于 1,则执行以下操作
    if (lenxp == 1) {
        # 将 dx 数组的第一个元素赋给 xp_val
        const npy_double xp_val = dx[0];
        # 将 dy 数组的第一个元素赋给 fp_val
        const npy_cdouble fp_val = dy[0];

        # 使用线程阈值启动多线程
        NPY_BEGIN_THREADS_THRESHOLDED(lenx);
        # 遍历 dz 数组中的元素
        for (i = 0; i < lenx; ++i) {
            # 将 dz 数组中第 i 个元素赋给 x_val
            const npy_double x_val = dz[i];
            # 根据 x_val 和 xp_val 的比较结果,选择合适的值赋给 dres[i]
            dres[i] = (x_val < xp_val) ? lval :
                      ((x_val > xp_val) ? rval : fp_val);
        }
        # 结束多线程区块
        NPY_END_THREADS;
    }
    else {
        // 初始化变量 j 为 0
        npy_intp j = 0;
    
        /* only pre-calculate slopes if there are relatively few of them. */
        // 仅在斜率相对较少时预先计算斜率
        if (lenxp <= lenx) {
            // 分配内存以存储斜率数组,长度为 (lenxp - 1)
            slopes = PyArray_malloc((lenxp - 1) * sizeof(npy_cdouble));
            // 如果内存分配失败,设置内存错误并跳转到失败标签
            if (slopes == NULL) {
                PyErr_NoMemory();
                goto fail;
            }
        }
    
        NPY_BEGIN_THREADS; // 开始线程安全操作
    
        // 如果斜率数组非空,则计算斜率
        if (slopes != NULL) {
            for (i = 0; i < lenxp - 1; ++i) {
                // 计算斜率的实部和虚部
                const double inv_dx = 1.0 / (dx[i+1] - dx[i]);
                npy_csetreal(&slopes[i], (npy_creal(dy[i+1]) - npy_creal(dy[i])) * inv_dx);
                npy_csetimag(&slopes[i], (npy_cimag(dy[i+1]) - npy_cimag(dy[i])) * inv_dx);
            }
        }
    
        // 遍历输入数组的元素
        for (i = 0; i < lenx; ++i) {
            // 获取当前输入值 x_val
            const npy_double x_val = dz[i];
    
            // 如果 x_val 是 NaN,则将结果设置为 x_val 的实部为 NaN,虚部为 0
            if (npy_isnan(x_val)) {
                npy_csetreal(&dres[i], x_val);
                npy_csetimag(&dres[i], 0.0);
                continue; // 继续下一个循环
            }
    
            // 使用二分搜索找到 x_val 在 dx 中的位置 j
            j = binary_search_with_guess(x_val, dx, lenxp, j);
    
            // 根据搜索的结果 j 进行插值操作或者直接返回边界值
            if (j == -1) {
                dres[i] = lval;
            }
            else if (j == lenxp) {
                dres[i] = rval;
            }
            else if (j == lenxp - 1) {
                dres[i] = dy[j];
            }
            else if (dx[j] == x_val) {
                /* Avoid potential non-finite interpolation */
                dres[i] = dy[j];
            }
            else {
                npy_cdouble slope;
                // 如果斜率数组非空,则使用预先计算的斜率
                if (slopes != NULL) {
                    slope = slopes[j];
                }
                // 否则根据两个相邻点的差值计算斜率
                else {
                    const npy_double inv_dx = 1.0 / (dx[j+1] - dx[j]);
                    npy_csetreal(&slope, (npy_creal(dy[j+1]) - npy_creal(dy[j])) * inv_dx);
                    npy_csetimag(&slope, (npy_cimag(dy[j+1]) - npy_cimag(dy[j])) * inv_dx);
                }
    
                // 进行线性插值计算,同时处理可能出现的 NaN
                npy_csetreal(&dres[i], npy_creal(slope)*(x_val - dx[j]) + npy_creal(dy[j]));
                if (NPY_UNLIKELY(npy_isnan(npy_creal(dres[i])))) {
                    npy_csetreal(&dres[i], npy_creal(slope)*(x_val - dx[j+1]) + npy_creal(dy[j+1]));
                    if (NPY_UNLIKELY(npy_isnan(npy_creal(dres[i]))) &&
                            npy_creal(dy[j]) == npy_creal(dy[j+1])) {
                        npy_csetreal(&dres[i], npy_creal(dy[j]));
                    }
                }
                npy_csetimag(&dres[i], npy_cimag(slope)*(x_val - dx[j]) + npy_cimag(dy[j]));
                if (NPY_UNLIKELY(npy_isnan(npy_cimag(dres[i])))) {
                    npy_csetimag(&dres[i], npy_cimag(slope)*(x_val - dx[j+1]) + npy_cimag(dy[j+1]));
                    if (NPY_UNLIKELY(npy_isnan(npy_cimag(dres[i]))) &&
                            npy_cimag(dy[j]) == npy_cimag(dy[j+1])) {
                        npy_csetimag(&dres[i], npy_cimag(dy[j]));
                    }
                }
            }
        }
    
        NPY_END_THREADS; // 结束线程安全操作
    }
    # 释放 slopes 数组占用的内存
    PyArray_free(slopes);
    
    # 递减引用计数,可能释放 afp 所引用对象的内存
    Py_DECREF(afp);
    
    # 递减引用计数,可能释放 axp 所引用对象的内存
    Py_DECREF(axp);
    
    # 递减引用计数,可能释放 ax 所引用对象的内存
    Py_DECREF(ax);
    
    # 返回一个 Python 对象,该对象是 af 的 NumPy 数组表示
    return PyArray_Return(af);
/* 
 * 清理和释放资源,然后返回 NULL,表示失败
 */
fail:
    Py_XDECREF(afp);
    Py_XDECREF(axp);
    Py_XDECREF(ax);
    Py_XDECREF(af);
    return NULL;
}

/*
 * 空序列错误信息,用于指示非整数索引的情况
 */
static const char *EMPTY_SEQUENCE_ERR_MSG = "indices must be integral: the provided " \
    "empty sequence was inferred as float. Wrap it with " \
    "'np.array(indices, dtype=np.intp)'";

/*
 * 非整数错误信息,仅允许整数索引
 */
static const char *NON_INTEGRAL_ERROR_MSG = "only int indices permitted";

/* 
 * 将 Python 对象 obj 转换为具有整数 dtype 的 ndarray,或者转换失败
 */
static PyArrayObject *
astype_anyint(PyObject *obj) {
    PyArrayObject *ret;

    if (!PyArray_Check(obj)) {
        /* 首选 int dtype */
        PyArray_Descr *dtype_guess = NULL;
        if (PyArray_DTypeFromObject(obj, NPY_MAXDIMS, &dtype_guess) < 0) {
            return NULL;
        }
        if (dtype_guess == NULL) {
            if (PySequence_Check(obj) && PySequence_Size(obj) == 0) {
                PyErr_SetString(PyExc_TypeError, EMPTY_SEQUENCE_ERR_MSG);
            }
            return NULL;
        }
        ret = (PyArrayObject*)PyArray_FromAny(obj, dtype_guess, 0, 0, 0, NULL);
        if (ret == NULL) {
            return NULL;
        }
    }
    else {
        ret = (PyArrayObject *)obj;
        Py_INCREF(ret);
    }

    if (!(PyArray_ISINTEGER(ret) || PyArray_ISBOOL(ret))) {
        /* 确保 dtype 是基于 int 的 */
        PyErr_SetString(PyExc_TypeError, NON_INTEGRAL_ERROR_MSG);
        Py_DECREF(ret);
        return NULL;
    }

    return ret;
}

/*
 * 将 Python 序列转换为 'count' 个 PyArrayObject 数组
 *
 * seq         - 输入的 Python 对象,通常是一个元组,但任何序列都可以工作。
 *               必须包含整数内容。
 * paramname   - 产生 'seq' 的参数名称。
 * count       - 应该有多少数组(如果不匹配则报错)。
 * op          - 数组的存放位置。
 */
static int int_sequence_to_arrays(PyObject *seq,
                              char *paramname,
                              int count,
                              PyArrayObject **op
                              )
{
    int i;

    if (!PySequence_Check(seq) || PySequence_Size(seq) != count) {
        PyErr_Format(PyExc_ValueError,
                "parameter %s must be a sequence of length %d",
                paramname, count);
        return -1;
    }

    for (i = 0; i < count; ++i) {
        PyObject *item = PySequence_GetItem(seq, i);
        if (item == NULL) {
            goto fail;
        }
        op[i] = astype_anyint(item);
        Py_DECREF(item);
        if (op[i] == NULL) {
            goto fail;
        }
    }

    return 0;

fail:
    while (--i >= 0) {
        Py_XDECREF(op[i]);
        op[i] = NULL;
    }
    return -1;
}

/* 
 * ravel_multi_index 的内部循环
 */
static int
ravel_multi_index_loop(int ravel_ndim, npy_intp *ravel_dims,
                        npy_intp *ravel_strides,
                        npy_intp count,
                        NPY_CLIPMODE *modes,
                        char **coords, npy_intp *coords_strides)
{
    int i;
    char invalid;
    npy_intp j, m;

    /*
     * 检查是否存在零维的轴,除非没有需要处理的情况。
     * 空数组/形状根本无法进行索引。
     */
    if (count != 0) {
        // 遍历展平后的维度数组
        for (i = 0; i < ravel_ndim; ++i) {
            // 如果有任何一个维度为0,抛出数值错误异常
            if (ravel_dims[i] == 0) {
                PyErr_SetString(PyExc_ValueError,
                        "cannot unravel if shape has zero entries (is empty).");
                return NPY_FAIL;
            }
        }
    }

    // 允许线程进入临界区域
    NPY_BEGIN_ALLOW_THREADS;
    invalid = 0;
    // 循环处理每个索引
    while (count--) {
        npy_intp raveled = 0;
        // 遍历展平后的维度数组
        for (i = 0; i < ravel_ndim; ++i) {
            m = ravel_dims[i];
            // 获取当前坐标的索引值
            j = *(npy_intp *)coords[i];
            switch (modes[i]) {
                case NPY_RAISE:
                    // 如果索引超出了范围,设置无效标志并跳出循环
                    if (j < 0 || j >= m) {
                        invalid = 1;
                        goto end_while;
                    }
                    break;
                case NPY_WRAP:
                    // 对超出范围的索引进行循环包裹
                    if (j < 0) {
                        j += m;
                        if (j < 0) {
                            j = j % m;
                            if (j != 0) {
                                j += m;
                            }
                        }
                    }
                    else if (j >= m) {
                        j -= m;
                        if (j >= m) {
                            j = j % m;
                        }
                    }
                    break;
                case NPY_CLIP:
                    // 对超出范围的索引进行截断处理
                    if (j < 0) {
                        j = 0;
                    }
                    else if (j >= m) {
                        j = m - 1;
                    }
                    break;

            }
            // 计算展平后的索引值
            raveled += j * ravel_strides[i];

            coords[i] += coords_strides[i];
        }
        // 将展平后的索引值写入坐标数组
        *(npy_intp *)coords[ravel_ndim] = raveled;
        coords[ravel_ndim] += coords_strides[ravel_ndim];
    }
end_while:
    NPY_END_ALLOW_THREADS;
    // 结束线程安全区域
    if (invalid) {
        // 如果坐标数组中存在无效项,设置值错误异常并返回失败状态
        PyErr_SetString(PyExc_ValueError,
              "invalid entry in coordinates array");
        return NPY_FAIL;
    }
    // 返回成功状态
    return NPY_SUCCEED;
}

/* ravel_multi_index implementation - see add_newdocs.py */
NPY_NO_EXPORT PyObject *
arr_ravel_multi_index(PyObject *self, PyObject *args, PyObject *kwds)
{
    int i;
    PyObject *mode0=NULL, *coords0=NULL;
    PyArrayObject *ret = NULL;
    PyArray_Dims dimensions={0,0};
    npy_intp s, ravel_strides[NPY_MAXDIMS];
    NPY_ORDER order = NPY_CORDER;
    NPY_CLIPMODE modes[NPY_MAXDIMS];

    PyArrayObject *op[NPY_MAXARGS];
    PyArray_Descr *dtype[NPY_MAXARGS];
    npy_uint32 op_flags[NPY_MAXARGS];

    NpyIter *iter = NULL;

    static char *kwlist[] = {"multi_index", "dims", "mode", "order", NULL};

    // 初始化操作数组和数据类型数组
    memset(op, 0, sizeof(op));
    dtype[0] = NULL;

    // 解析参数和关键字参数
    if (!PyArg_ParseTupleAndKeywords(args, kwds,
                        "OO&|OO&:ravel_multi_index", kwlist,
                     &coords0,
                     PyArray_IntpConverter, &dimensions,
                     &mode0,
                     PyArray_OrderConverter, &order)) {
        goto fail;
    }

    // 检查维度数量是否超过最大值
    if (dimensions.len+1 > NPY_MAXARGS) {
        PyErr_SetString(PyExc_ValueError,
                    "too many dimensions passed to ravel_multi_index");
        goto fail;
    }

    // 转换并检查剪切模式序列
    if (!PyArray_ConvertClipmodeSequence(mode0, modes, dimensions.len)) {
       goto fail;
    }

    // 根据顺序计算展平步长
    switch (order) {
        case NPY_CORDER:
            s = 1;
            for (i = dimensions.len-1; i >= 0; --i) {
                ravel_strides[i] = s;
                if (npy_mul_sizes_with_overflow(&s, s, dimensions.ptr[i])) {
                    PyErr_SetString(PyExc_ValueError,
                        "invalid dims: array size defined by dims is larger "
                        "than the maximum possible size.");
                    goto fail;
                }
            }
            break;
        case NPY_FORTRANORDER:
            s = 1;
            for (i = 0; i < dimensions.len; ++i) {
                ravel_strides[i] = s;
                if (npy_mul_sizes_with_overflow(&s, s, dimensions.ptr[i])) {
                    PyErr_SetString(PyExc_ValueError,
                        "invalid dims: array size defined by dims is larger "
                        "than the maximum possible size.");
                    goto fail;
                }
            }
            break;
        default:
            PyErr_SetString(PyExc_ValueError,
                            "only 'C' or 'F' order is permitted");
            goto fail;
    }

    // 将多索引转换为操作数组
    if (int_sequence_to_arrays(coords0, "multi_index", dimensions.len, op) < 0) {
        goto fail;
    }

    // 设置操作数组的标志
    for (i = 0; i < dimensions.len; ++i) {
        op_flags[i] = NPY_ITER_READONLY|
                      NPY_ITER_ALIGNED;
    }
    # 将操作标志设置为写入、对齐和分配内存的组合
    op_flags[dimensions.len] = NPY_ITER_WRITEONLY|
                               NPY_ITER_ALIGNED|
                               NPY_ITER_ALLOCATE;
    # 使用整数类型创建第一个数据类型描述符
    dtype[0] = PyArray_DescrFromType(NPY_INTP);
    # 复制第一个数据类型描述符到所有维度中
    for (i = 1; i <= dimensions.len; ++i) {
        dtype[i] = dtype[0];
    }

    # 创建多迭代器对象,设置迭代器的特性
    iter = NpyIter_MultiNew(dimensions.len+1, op, NPY_ITER_BUFFERED|
                                                  NPY_ITER_EXTERNAL_LOOP|
                                                  NPY_ITER_ZEROSIZE_OK,
                                                  NPY_KEEPORDER,
                                                  NPY_SAME_KIND_CASTING,
                                                  op_flags, dtype);
    # 如果迭代器创建失败,则跳转到失败标签
    if (iter == NULL) {
        goto fail;
    }

    # 如果迭代器大小不为零,则执行迭代操作
    if (NpyIter_GetIterSize(iter) != 0) {
        # 获取迭代器的下一个迭代函数指针及相关指针
        NpyIter_IterNextFunc *iternext;
        char **dataptr;
        npy_intp *strides;
        npy_intp *countptr;

        iternext = NpyIter_GetIterNext(iter, NULL);
        # 如果获取迭代函数失败,则跳转到失败标签
        if (iternext == NULL) {
            goto fail;
        }
        # 获取数据指针数组、步长数组和内循环大小指针
        dataptr = NpyIter_GetDataPtrArray(iter);
        strides = NpyIter_GetInnerStrideArray(iter);
        countptr = NpyIter_GetInnerLoopSizePtr(iter);

        # 执行多维索引展开循环,如果失败则跳转到失败标签
        do {
            if (ravel_multi_index_loop(dimensions.len, dimensions.ptr,
                        ravel_strides, *countptr, modes,
                        dataptr, strides) != NPY_SUCCEED) {
                goto fail;
            }
        } while(iternext(iter));
    }

    # 获取操作数数组中的返回值
    ret = NpyIter_GetOperandArray(iter)[dimensions.len];
    # 增加返回值的引用计数
    Py_INCREF(ret);

    # 释放第一个数据类型描述符的引用
    Py_DECREF(dtype[0]);
    # 释放操作数数组中的每个操作数的引用
    for (i = 0; i < dimensions.len; ++i) {
        Py_XDECREF(op[i]);
    }
    # 释放维度缓存对象
    npy_free_cache_dim_obj(dimensions);
    # 释放迭代器对象
    NpyIter_Deallocate(iter);
    # 返回返回值的 Python 对象表示
    return PyArray_Return(ret);
fail:
    // 释放 dtype[0] 指向的对象,减少其引用计数
    Py_XDECREF(dtype[0]);
    // 循环释放 op 数组中每个元素指向的对象,减少它们的引用计数
    for (i = 0; i < dimensions.len; ++i) {
        Py_XDECREF(op[i]);
    }
    // 释放 dimensions 所占用的内存
    npy_free_cache_dim_obj(dimensions);
    // 释放 NpyIter 迭代器所占用的资源
    NpyIter_Deallocate(iter);
    // 返回 NULL,表示操作失败
    return NULL;
}


/*
 * Inner loop for unravel_index
 * order must be NPY_CORDER or NPY_FORTRANORDER
 */
static int
unravel_index_loop(int unravel_ndim, npy_intp const *unravel_dims,
                   npy_intp unravel_size, npy_intp count,
                   char *indices, npy_intp indices_stride,
                   npy_intp *coords, NPY_ORDER order)
{
    int i, idx;
    // 根据 order 设置起始索引位置和步长
    int idx_start = (order == NPY_CORDER) ? unravel_ndim - 1: 0;
    int idx_step = (order == NPY_CORDER) ? -1 : 1;
    char invalid = 0;
    npy_intp val = 0;

    NPY_BEGIN_ALLOW_THREADS;
    // 断言 order 必须是 NPY_CORDER 或 NPY_FORTRANORDER
    assert(order == NPY_CORDER || order == NPY_FORTRANORDER);
    while (count--) {
        // 从 indices 中读取当前的 val 值
        val = *(npy_intp *)indices;
        // 检查 val 是否在合法范围内
        if (val < 0 || val >= unravel_size) {
            invalid = 1;
            break;
        }
        idx = idx_start;
        for (i = 0; i < unravel_ndim; ++i) {
            /*
             * 使用一个局部变量可能启用单一的除法优化
             * 但是只有在 / 操作符在 % 操作符之前时才会生效
             */
            npy_intp tmp = val / unravel_dims[idx];
            // 计算当前坐标的值,并更新 coords 数组
            coords[idx] = val % unravel_dims[idx];
            // 更新 val 为下一个维度的坐标值
            val = tmp;
            // 根据步长更新 idx 索引
            idx += idx_step;
        }
        // 更新 coords 和 indices 的指针位置
        coords += unravel_ndim;
        indices += indices_stride;
    }
    NPY_END_ALLOW_THREADS;
    // 如果发现索引超出范围,抛出异常并返回失败标志
    if (invalid) {
        PyErr_Format(PyExc_ValueError,
            "index %" NPY_INTP_FMT " is out of bounds for array with size "
            "%" NPY_INTP_FMT,
            val, unravel_size
        );
        return NPY_FAIL;
    }
    // 操作成功,返回成功标志
    return NPY_SUCCEED;
}

/* unravel_index implementation - see add_newdocs.py */
NPY_NO_EXPORT PyObject *
arr_unravel_index(PyObject *self, PyObject *args, PyObject *kwds)
{
    PyObject *indices0 = NULL;
    PyObject *ret_tuple = NULL;
    PyArrayObject *ret_arr = NULL;
    PyArrayObject *indices = NULL;
    PyArray_Descr *dtype = NULL;
    PyArray_Dims dimensions = {0, 0};
    NPY_ORDER order = NPY_CORDER;
    npy_intp unravel_size;

    NpyIter *iter = NULL;
    int i, ret_ndim;
    npy_intp ret_dims[NPY_MAXDIMS], ret_strides[NPY_MAXDIMS];

    static char *kwlist[] = {"indices", "shape", "order", NULL};

    // 解析输入参数,获取 indices、dimensions 和 order
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO&|O&:unravel_index",
                    kwlist,
                    &indices0,
                    PyArray_IntpConverter, &dimensions,
                    PyArray_OrderConverter, &order)) {
        // 解析失败,跳转到 fail 标签处
        goto fail;
    }

    // 计算 unravel_size,即 dimensions 中所有元素的乘积
    unravel_size = PyArray_OverflowMultiplyList(dimensions.ptr, dimensions.len);
    // 检查是否计算溢出
    if (unravel_size == -1) {
        // 如果溢出,抛出 ValueError 异常并跳转到 fail 标签处
        PyErr_SetString(PyExc_ValueError,
                        "dimensions are too large; arrays and shapes with "
                        "a total size greater than 'intp' are not supported.");
        goto fail;
    }
    indices = astype_anyint(indices0);
    # 将输入的indices0转换为任意整数类型的数组indices
    if (indices == NULL) {
        goto fail;
    }

    dtype = PyArray_DescrFromType(NPY_INTP);
    # 创建一个描述器,表示NPY_INTP类型的数组
    if (dtype == NULL) {
        goto fail;
    }

    iter = NpyIter_New(indices, NPY_ITER_READONLY|
                                NPY_ITER_ALIGNED|
                                NPY_ITER_BUFFERED|
                                NPY_ITER_ZEROSIZE_OK|
                                NPY_ITER_DONT_NEGATE_STRIDES|
                                NPY_ITER_MULTI_INDEX,
                                NPY_KEEPORDER, NPY_SAME_KIND_CASTING,
                                dtype);
    # 使用indices创建一个迭代器,设置迭代器的属性和类型
    if (iter == NULL) {
        goto fail;
    }

    /*
     * Create the return array with a layout compatible with the indices
     * and with a dimension added to the end for the multi-index
     */
    // 创建一个返回数组,其布局与indices兼容,并在末尾增加一个维度用于多索引
    ret_ndim = PyArray_NDIM(indices) + 1;
    if (NpyIter_GetShape(iter, ret_dims) != NPY_SUCCEED) {
        goto fail;
    }
    // 获取返回数组的维度,并设置最后一个维度为dimensions.len
    ret_dims[ret_ndim-1] = dimensions.len;
    if (NpyIter_CreateCompatibleStrides(iter,
                dimensions.len*sizeof(npy_intp), ret_strides) != NPY_SUCCEED) {
        goto fail;
    }
    // 创建与迭代器兼容的步幅,并设置最后一个维度的步幅为sizeof(npy_intp)

    /* Remove the multi-index and inner loop */
    // 移除多索引和内部循环
    if (NpyIter_RemoveMultiIndex(iter) != NPY_SUCCEED) {
        goto fail;
    }
    // 移除迭代器的多索引功能
    if (NpyIter_EnableExternalLoop(iter) != NPY_SUCCEED) {
        goto fail;
    }
    // 启用外部循环功能

    ret_arr = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, dtype,
                            ret_ndim, ret_dims, ret_strides, NULL, 0, NULL);
    // 使用描述器创建一个新的PyArrayObject作为返回数组
    dtype = NULL;
    if (ret_arr == NULL) {
        goto fail;
    }

    if (order != NPY_CORDER && order != NPY_FORTRANORDER) {
        PyErr_SetString(PyExc_ValueError,
                        "only 'C' or 'F' order is permitted");
        goto fail;
    }
    // 检查order是否为NPY_CORDER或NPY_FORTRANORDER,否则设置错误并跳转到fail标签
    if (NpyIter_GetIterSize(iter) != 0) {
        NpyIter_IterNextFunc *iternext;
        char **dataptr;
        npy_intp *strides;
        npy_intp *countptr, count;
        npy_intp *coordsptr = (npy_intp *)PyArray_DATA(ret_arr);

        iternext = NpyIter_GetIterNext(iter, NULL);
        // 获取迭代器的下一个函数指针
        if (iternext == NULL) {
            goto fail;
        }
        // 如果获取失败则跳转到fail标签

        dataptr = NpyIter_GetDataPtrArray(iter);
        // 获取迭代器中数据指针的数组
        strides = NpyIter_GetInnerStrideArray(iter);
        // 获取迭代器中内部步幅的数组
        countptr = NpyIter_GetInnerLoopSizePtr(iter);
        // 获取迭代器中内部循环大小的指针

        do {
            count = *countptr;
            // 获取当前内部循环的大小
            if (unravel_index_loop(dimensions.len, dimensions.ptr,
                                   unravel_size, count, *dataptr, *strides,
                                   coordsptr, order) != NPY_SUCCEED) {
                goto fail;
            }
            // 对当前内部循环进行展开索引操作,如果失败则跳转到fail标签
            coordsptr += count * dimensions.len;
            // 更新coordsptr,移动到下一个内部循环的开始位置
        } while (iternext(iter));
        // 使用iternext函数进行迭代,直到迭代结束
    }
    /*
     * 如果 dimensions.len0 且 indices 的维度不为 0,
     * 表示对于零维数组没有索引意义上的“取唯一元素十次”操作,
     * 因此我们别无选择只能报错。(参见 gh-580)
     *
     * 在迭代完成后进行这个检查,这样可以为无效索引提供更好的错误消息。
     */
    if (dimensions.len == 0 && PyArray_NDIM(indices) != 0) {
        PyErr_SetString(PyExc_ValueError,
                "multiple indices are not supported for 0d arrays");
        goto fail;
    }

    /* 现在根据每个索引创建视图的元组 */
    ret_tuple = PyTuple_New(dimensions.len);
    if (ret_tuple == NULL) {
        goto fail;
    }
    for (i = 0; i < dimensions.len; ++i) {
        PyArrayObject *view;

        view = (PyArrayObject *)PyArray_NewFromDescrAndBase(
                &PyArray_Type, PyArray_DescrFromType(NPY_INTP),
                ret_ndim - 1, ret_dims, ret_strides,
                PyArray_BYTES(ret_arr) + i*sizeof(npy_intp),
                NPY_ARRAY_WRITEABLE, NULL, (PyObject *)ret_arr);
        if (view == NULL) {
            goto fail;
        }
        PyTuple_SET_ITEM(ret_tuple, i, PyArray_Return(view));
    }

    Py_DECREF(ret_arr);
    Py_XDECREF(indices);
    npy_free_cache_dim_obj(dimensions);
    NpyIter_Deallocate(iter);

    // 返回创建的视图元组
    return ret_tuple;
fail:
    // 释放 ret_tuple 所引用的 Python 对象,减少其引用计数
    Py_XDECREF(ret_tuple);
    // 释放 ret_arr 所引用的 Python 对象,减少其引用计数
    Py_XDECREF(ret_arr);
    // 释放 dtype 所引用的 Python 对象,减少其引用计数
    Py_XDECREF(dtype);
    // 释放 indices 所引用的 Python 对象,减少其引用计数
    Py_XDECREF(indices);
    // 释放之前分配的维度缓存对象
    npy_free_cache_dim_obj(dimensions);
    // 释放 NpyIter 对象及其内部资源
    NpyIter_Deallocate(iter);
    // 返回 NULL 指针,表示失败
    return NULL;
}

/* Can only be called if doc is currently NULL */
NPY_NO_EXPORT PyObject *
arr_add_docstring(PyObject *NPY_UNUSED(dummy), PyObject *const *args, Py_ssize_t len_args)
{
    PyObject *obj;
    PyObject *str;
    const char *docstr;
    static char *msg = "already has a different docstring";

    /* Don't add docstrings */
    // 如果 Python 解释器版本支持静态优化并且已启用,直接返回 None
#if PY_VERSION_HEX > 0x030b0000
    if (npy_static_cdata.optimize > 1) {
#else
    if (Py_OptimizeFlag > 1) {
#endif
        Py_RETURN_NONE;
    }

    // 准备解析参数
    NPY_PREPARE_ARGPARSER;
    // 解析参数,期望两个参数:一个对象和一个字符串
    if (npy_parse_arguments("add_docstring", args, len_args, NULL,
            "", NULL, &obj,
            "", NULL, &str,
            NULL, NULL, NULL) < 0) {
        return NULL;
    }
    // 确保传入的字符串参数是一个 Unicode 对象
    if (!PyUnicode_Check(str)) {
        PyErr_SetString(PyExc_TypeError,
                "argument docstring of add_docstring should be a str");
        return NULL;
    }

    // 将 Unicode 字符串转换为 UTF-8 格式的 C 字符串
    docstr = PyUnicode_AsUTF8(str);
    if (docstr == NULL) {
        return NULL;
    }

    // 定义宏 _ADDDOC,用于设置对象的文档字符串
#define _ADDDOC(doc, name)                                              \
        if (!(doc)) {                                                   \
            doc = docstr;                                               \
            Py_INCREF(str);  /* hold on to string (leaks reference) */  \
        }                                                               \
        else if (strcmp(doc, docstr) != 0) {                            \
            PyErr_Format(PyExc_RuntimeError, "%s method %s", name, msg); \
            return NULL;                                                \
        }

    // 根据对象类型设置相应的文档字符串
    if (Py_TYPE(obj) == &PyCFunction_Type) {
        // 如果是 C 函数对象,则设置其 ml_doc 字段为传入的文档字符串
        PyCFunctionObject *new = (PyCFunctionObject *)obj;
        _ADDDOC(new->m_ml->ml_doc, new->m_ml->ml_name);
    }
    else if (PyObject_TypeCheck(obj, &PyType_Type)) {
        // 如果是 Python 类型对象,则设置其 tp_doc 字段和 __doc__ 字典项为传入的文档字符串
        PyTypeObject *new = (PyTypeObject *)obj;
        _ADDDOC(new->tp_doc, new->tp_name);
        // 如果 tp_dict 不为空且 __doc__ 项为 None,则替换为传入的文档字符串
        if (new->tp_dict != NULL && PyDict_CheckExact(new->tp_dict) &&
                PyDict_GetItemString(new->tp_dict, "__doc__") == Py_None) {
            // 警告:修改 tp_dict 不一定安全!
            if (PyDict_SetItemString(new->tp_dict, "__doc__", str) < 0) {
                return NULL;
            }
        }
    }
    # 如果对象的类型是 PyMemberDescr_Type
    else if (Py_TYPE(obj) == &PyMemberDescr_Type) {
        # 将 obj 转换为 PyMemberDescrObject 类型
        PyMemberDescrObject *new = (PyMemberDescrObject *)obj;
        # 调用 _ADDDOC 函数,将 new 对象的成员变量文档和名称传入
        _ADDDOC(new->d_member->doc, new->d_member->name);
    }
    # 如果对象的类型是 PyGetSetDescr_Type
    else if (Py_TYPE(obj) == &PyGetSetDescr_Type) {
        # 将 obj 转换为 PyGetSetDescrObject 类型
        PyGetSetDescrObject *new = (PyGetSetDescrObject *)obj;
        # 调用 _ADDDOC 函数,将 new 对象的获取设置文档和名称传入
        _ADDDOC(new->d_getset->doc, new->d_getset->name);
    }
    # 如果对象的类型是 PyMethodDescr_Type
    else if (Py_TYPE(obj) == &PyMethodDescr_Type) {
        # 将 obj 转换为 PyMethodDescrObject 类型
        PyMethodDescrObject *new = (PyMethodDescrObject *)obj;
        # 调用 _ADDDOC 函数,将 new 对象的方法文档和名称传入
        _ADDDOC(new->d_method->ml_doc, new->d_method->ml_name);
    }
    # 如果对象不属于上述三种类型
    else {
        PyObject *doc_attr;

        # 获取对象的 "__doc__" 属性
        doc_attr = PyObject_GetAttrString(obj, "__doc__");
        # 如果获取成功且不为 None,并且对象的 __doc__ 属性与 str 不相等
        if (doc_attr != NULL && doc_attr != Py_None &&
                (PyUnicode_Compare(doc_attr, str) != 0)) {
            Py_DECREF(doc_attr);
            # 如果在比较时发生错误
            if (PyErr_Occurred()) {
                /* error during PyUnicode_Compare */
                return NULL;
            }
            # 抛出运行时错误,指明对象的信息
            PyErr_Format(PyExc_RuntimeError, "object %s", msg);
            return NULL;
        }
        Py_XDECREF(doc_attr);

        # 将对象的 "__doc__" 属性设置为 str
        if (PyObject_SetAttrString(obj, "__doc__", str) < 0) {
            # 如果设置失败,抛出类型错误
            PyErr_SetString(PyExc_TypeError,
                            "Cannot set a docstring for that object");
            return NULL;
        }
        # 返回 None
        Py_RETURN_NONE;
    }
/*
 * 返回一个 Python None 对象,表示函数执行完毕没有返回值。
 */
Py_RETURN_NONE;
}

/*
 * 此函数将输入数组中的布尔值打包到字节数组的位中。布尔真值按常规方式确定:0为假,其他值为真。
 */
static NPY_GCC_OPT_3 inline void
pack_inner(const char *inptr,
           npy_intp element_size,   /* 每个元素的大小,以字节为单位 */
           npy_intp n_in,           /* 输入数组中的元素数量 */
           npy_intp in_stride,      /* 输入数组的步幅 */
           char *outptr,
           npy_intp n_out,          /* 输出数组的元素数量 */
           npy_intp out_stride,     /* 输出数组的步幅 */
           PACK_ORDER order)        /* 打包顺序 */
{
    /*
     * 遍历 inptr 的元素。
     * 确定它是否为非零值。
     *   是:设置对应的位(并调整构建值)
     *   否:继续下一个元素
     * 每8个值,设置构建值并递增 outptr
     */
    npy_intp index = 0;
    int remain = n_in % 8;              /* 不均匀的位数 */

#if NPY_SIMD
    // 检查条件:输入步长为1、元素大小为1字节、输出数量大于2时进入条件块
    if (in_stride == 1 && element_size == 1 && n_out > 2) {
        // 创建全零的8位整数向量
        npyv_u8 v_zero = npyv_zero_u8();
        /* 不处理非完整的8字节余数 */
        // 计算有效输出数量,排除余数的影响
        npy_intp vn_out = n_out - (remain ? 1 : 0);
        // 设置向量步长为64位
        const int vstep = npyv_nlanes_u64;
        // 设置4倍向量步长
        const int vstepx4 = vstep * 4;
        // 检查输出指针是否按64位对齐
        const int isAligned = npy_is_aligned(outptr, sizeof(npy_uint64));
        // 调整有效输出数量,使其按向量步长对齐
        vn_out -= (vn_out & (vstep - 1));
        // 循环处理主体,以向量步长x4为单位处理数据
        for (; index <= vn_out - vstepx4; index += vstepx4, inptr += npyv_nlanes_u8 * 4) {
            // 加载4个8位整数向量
            npyv_u8 v0 = npyv_load_u8((const npy_uint8*)inptr);
            npyv_u8 v1 = npyv_load_u8((const npy_uint8*)inptr + npyv_nlanes_u8 * 1);
            npyv_u8 v2 = npyv_load_u8((const npy_uint8*)inptr + npyv_nlanes_u8 * 2);
            npyv_u8 v3 = npyv_load_u8((const npy_uint8*)inptr + npyv_nlanes_u8 * 3);
            // 如果顺序为大端,反转每个8位整数向量
            if (order == PACK_ORDER_BIG) {
                v0 = npyv_rev64_u8(v0);
                v1 = npyv_rev64_u8(v1);
                v2 = npyv_rev64_u8(v2);
                v3 = npyv_rev64_u8(v3);
            }
            // 定义一个64位整数数组
            npy_uint64 bb[4];
            // 将每个8位整数向量转换为比特表示,并存储到数组中
            bb[0] = npyv_tobits_b8(npyv_cmpneq_u8(v0, v_zero));
            bb[1] = npyv_tobits_b8(npyv_cmpneq_u8(v1, v_zero));
            bb[2] = npyv_tobits_b8(npyv_cmpneq_u8(v2, v_zero));
            bb[3] = npyv_tobits_b8(npyv_cmpneq_u8(v3, v_zero));
            // 如果输出步长为1且满足对齐要求或者不需要对齐
            if(out_stride == 1 && 
                (!NPY_ALIGNMENT_REQUIRED || isAligned)) {
                // 强制类型转换为64位整数指针
                npy_uint64 *ptr64 = (npy_uint64*)outptr;
                // 根据 SIMD 宽度执行不同的位运算和存储操作
                #if NPY_SIMD_WIDTH == 16
                    npy_uint64 bcomp = bb[0] | (bb[1] << 16) | (bb[2] << 32) | (bb[3] << 48);
                    ptr64[0] = bcomp;
                #elif NPY_SIMD_WIDTH == 32
                    ptr64[0] = bb[0] | (bb[1] << 32);
                    ptr64[1] = bb[2] | (bb[3] << 32);
                #else
                    ptr64[0] = bb[0]; ptr64[1] = bb[1];
                    ptr64[2] = bb[2]; ptr64[3] = bb[3];
                #endif
                // 更新输出指针位置
                outptr += vstepx4;
            } else {
                // 如果输出步长不为1或者需要对齐,逐位复制数据到输出指针
                for(int i = 0; i < 4; i++) {
                    for (int j = 0; j < vstep; j++) {
                        memcpy(outptr, (char*)&bb[i] + j, 1);
                        outptr += out_stride;
                    }
                }
            }
        }
        // 处理剩余的向量元素,不足一组的部分
        for (; index < vn_out; index += vstep, inptr += npyv_nlanes_u8) {
            // 加载一个8位整数向量
            npyv_u8 va = npyv_load_u8((const npy_uint8*)inptr);
            // 如果顺序为大端,反转该8位整数向量
            if (order == PACK_ORDER_BIG) {
                va = npyv_rev64_u8(va);
            }
            // 将该8位整数向量转换为比特表示
            npy_uint64 bb = npyv_tobits_b8(npyv_cmpneq_u8(va, v_zero));
            // 逐位复制数据到输出指针
            for (int i = 0; i < vstep; ++i) {
                memcpy(outptr, (char*)&bb + i, 1);
                outptr += out_stride;
            }
        }
    }
#endif

    if (remain == 0) {                  /* assumes n_in > 0 */
        remain = 8;
    }
    /* 不重置索引,只处理上面代码块的剩余部分 */
    for (; index < n_out; index++) {
        unsigned char build = 0;
        int maxi = (index == n_out - 1) ? remain : 8;
        if (order == PACK_ORDER_BIG) {
            // 大端序
            for (int i = 0; i < maxi; i++) {
                build <<= 1;
                for (npy_intp j = 0; j < element_size; j++) {
                    build |= (inptr[j] != 0);
                }
                inptr += in_stride;
            }
            if (index == n_out - 1) {
                build <<= 8 - remain;
            }
        }
        else
        {
            // 小端序
            for (int i = 0; i < maxi; i++) {
                build >>= 1;
                for (npy_intp j = 0; j < element_size; j++) {
                    build |= (inptr[j] != 0) ? 128 : 0;
                }
                inptr += in_stride;
            }
            if (index == n_out - 1) {
                build >>= 8 - remain;
            }
        }
        *outptr = (char)build;
        outptr += out_stride;
    }
}

static PyObject *
pack_bits(PyObject *input, int axis, char order)
{
    PyArrayObject *inp;
    PyArrayObject *new = NULL;
    PyArrayObject *out = NULL;
    npy_intp outdims[NPY_MAXDIMS];
    int i;
    PyArrayIterObject *it, *ot;
    NPY_BEGIN_THREADS_DEF;

    inp = (PyArrayObject *)PyArray_FROM_O(input);

    if (inp == NULL) {
        return NULL;
    }
    if (!PyArray_ISBOOL(inp) && !PyArray_ISINTEGER(inp)) {
        PyErr_SetString(PyExc_TypeError,
                "Expected an input array of integer or boolean data type");
        Py_DECREF(inp);
        goto fail;
    }

    new = (PyArrayObject *)PyArray_CheckAxis(inp, &axis, 0);
    Py_DECREF(inp);
    if (new == NULL) {
        return NULL;
    }

    if (PyArray_NDIM(new) == 0) {
        char *optr, *iptr;

        out = (PyArrayObject *)PyArray_NewFromDescr(
                Py_TYPE(new), PyArray_DescrFromType(NPY_UBYTE),
                0, NULL, NULL, NULL,
                0, NULL);
        if (out == NULL) {
            goto fail;
        }
        optr = PyArray_DATA(out);
        iptr = PyArray_DATA(new);
        *optr = 0;
        for (i = 0; i < PyArray_ITEMSIZE(new); i++) {
            if (*iptr != 0) {
                *optr = 1;
                break;
            }
            iptr++;
        }
        goto finish;
    }


    /* 设置输出形状 */
    for (i = 0; i < PyArray_NDIM(new); i++) {
        outdims[i] = PyArray_DIM(new, i);
    }

    /*
     * 将轴的维度除以8
     * 8 -> 1, 9 -> 2, 16 -> 2, 17 -> 3 等等..
     */
    outdims[axis] = ((outdims[axis] - 1) >> 3) + 1;

    /* 创建输出数组 */
    out = (PyArrayObject *)PyArray_NewFromDescr(
            Py_TYPE(new), PyArray_DescrFromType(NPY_UBYTE),
            PyArray_NDIM(new), outdims, NULL, NULL,
            PyArray_ISFORTRAN(new), NULL);
    if (out == NULL) {
        goto fail;
    }
    # 设置迭代器以便在除了给定轴以外的所有维度上进行迭代
    it = (PyArrayIterObject *)PyArray_IterAllButAxis((PyObject *)new, &axis);
    ot = (PyArrayIterObject *)PyArray_IterAllButAxis((PyObject *)out, &axis);
    # 如果迭代器初始化失败,则释放资源并跳转到错误处理部分
    if (it == NULL || ot == NULL) {
        Py_XDECREF(it);
        Py_XDECREF(ot);
        goto fail;
    }
    # 根据给定的字节序列创建一个枚举类型,'b'表示大端序,'l'表示小端序
    const PACK_ORDER ordere = order == 'b' ? PACK_ORDER_BIG : PACK_ORDER_LITTLE;
    # 多线程处理的起始点,根据输出数组在给定轴上的维度进行决定
    NPY_BEGIN_THREADS_THRESHOLDED(PyArray_DIM(out, axis));
    # 迭代处理数组中的每个元素
    while (PyArray_ITER_NOTDONE(it)) {
        # 调用内部函数,对数组中的数据进行打包处理
        pack_inner(PyArray_ITER_DATA(it), PyArray_ITEMSIZE(new),
                   PyArray_DIM(new, axis), PyArray_STRIDE(new, axis),
                   PyArray_ITER_DATA(ot), PyArray_DIM(out, axis),
                   PyArray_STRIDE(out, axis), ordere);
        # 移动到下一个元素
        PyArray_ITER_NEXT(it);
        PyArray_ITER_NEXT(ot);
    }
    # 多线程处理结束
    NPY_END_THREADS;

    # 释放迭代器对象
    Py_DECREF(it);
    Py_DECREF(ot);
    // 释放新建对象的 Python 引用计数,避免内存泄漏
    Py_DECREF(new);
    // 返回输出对象的 PyObject 指针类型,完成函数执行
    return (PyObject *)out;

fail:
    // 出错处理:释放新建对象的 Python 引用计数
    Py_XDECREF(new);
    // 出错处理:释放输出对象的 Python 引用计数
    Py_XDECREF(out);
    // 出错处理:返回空指针表示函数执行失败
    return NULL;
}



static PyObject *
unpack_bits(PyObject *input, int axis, PyObject *count_obj, char order)
{
    PyArrayObject *inp;
    PyArrayObject *new = NULL;
    PyArrayObject *out = NULL;
    npy_intp outdims[NPY_MAXDIMS];
    int i;
    PyArrayIterObject *it, *ot;
    npy_intp count, in_n, in_tail, out_pad, in_stride, out_stride;
    NPY_BEGIN_THREADS_DEF;

    // 从 Python 对象创建 PyArrayObject,转换为 NumPy 数组
    inp = (PyArrayObject *)PyArray_FROM_O(input);

    if (inp == NULL) {
        // 如果转换失败,返回空指针表示函数执行失败
        return NULL;
    }
    if (PyArray_TYPE(inp) != NPY_UBYTE) {
        // 如果输入数组不是无符号字节类型,设置错误信息并释放输入数组
        PyErr_SetString(PyExc_TypeError,
                "Expected an input array of unsigned byte data type");
        Py_DECREF(inp);
        // 转到出错处理标签
        goto fail;
    }

    // 检查轴的有效性,并返回新的 PyArrayObject
    new = (PyArrayObject *)PyArray_CheckAxis(inp, &axis, 0);
    Py_DECREF(inp);
    if (new == NULL) {
        // 如果检查轴失败,返回空指针表示函数执行失败
        return NULL;
    }

    if (PyArray_NDIM(new) == 0) {
        // 处理0维数组,将其转换为1维数组
        PyArrayObject *temp;
        PyArray_Dims newdim = {NULL, 1};
        npy_intp shape = 1;

        newdim.ptr = &shape;
        // 创建新形状的数组,并释放原数组
        temp = (PyArrayObject *)PyArray_Newshape(new, &newdim, NPY_CORDER);
        Py_DECREF(new);
        if (temp == NULL) {
            // 如果创建新形状数组失败,返回空指针表示函数执行失败
            return NULL;
        }
        new = temp;
    }

    // 设置输出数组的形状
    for (i = 0; i < PyArray_NDIM(new); i++) {
        outdims[i] = PyArray_DIM(new, i);
    }

    // 将指定轴的维度乘以8
    outdims[axis] *= 8;
    if (count_obj != Py_None) {
        // 如果 count_obj 不是 None,将其转换为整数并检查
        count = PyArray_PyIntAsIntp(count_obj);
        if (error_converting(count)) {
            // 如果转换失败,转到出错处理标签
            goto fail;
        }
        if (count < 0) {
            // 如果 count 是负数,调整输出数组的维度
            outdims[axis] += count;
            if (outdims[axis] < 0) {
                // 如果调整后的维度小于0,设置错误信息并转到出错处理标签
                PyErr_Format(PyExc_ValueError,
                             "-count larger than number of elements");
                goto fail;
            }
        }
        else {
            // 如果 count 是非负数,设置输出数组的维度为 count
            outdims[axis] = count;
        }
    }

    // 创建输出数组
    out = (PyArrayObject *)PyArray_NewFromDescr(
            Py_TYPE(new), PyArray_DescrFromType(NPY_UBYTE),
            PyArray_NDIM(new), outdims, NULL, NULL,
            PyArray_ISFORTRAN(new), NULL);
    if (out == NULL) {
        // 如果创建输出数组失败,转到出错处理标签
        goto fail;
    }

    // 设置迭代器,用于遍历除指定轴以外的所有维度
    it = (PyArrayIterObject *)PyArray_IterAllButAxis((PyObject *)new, &axis);
    ot = (PyArrayIterObject *)PyArray_IterAllButAxis((PyObject *)out, &axis);
    if (it == NULL || ot == NULL) {
        // 如果设置迭代器失败,释放迭代器并转到出错处理标签
        Py_XDECREF(it);
        Py_XDECREF(ot);
        goto fail;
    }

    // 计算输入数据的位数和填充要求
    count = PyArray_DIM(new, axis) * 8;
    if (outdims[axis] > count) {
        in_n = count / 8;
        in_tail = 0;
        out_pad = outdims[axis] - count;
    }
    else {
        in_n = outdims[axis] / 8;
        in_tail = outdims[axis] % 8;
        out_pad = 0;
    }

    // 计算输入和输出数组的步幅
    in_stride = PyArray_STRIDE(new, axis);
    out_stride = PyArray_STRIDE(out, axis);
    # 根据输出数组的大小设置线程阈值,用于多线程处理
    NPY_BEGIN_THREADS_THRESHOLDED(PyArray_Size((PyObject *)out) / 8);

    # 迭代器循环,直到迭代结束
    while (PyArray_ITER_NOTDONE(it)) {
        npy_intp index;
        # 获取输入迭代器的当前数据指针
        unsigned const char *inptr = PyArray_ITER_DATA(it);
        # 获取输出迭代器的当前数据指针
        char *outptr = PyArray_ITER_DATA(ot);

        # 如果输出步长为1
        if (out_stride == 1) {
            /* 对于单位步长,可以直接从查找表中复制数据 */
            if (order == 'b') {
                # 按字节顺序(大端)循环处理输入数据
                for (index = 0; index < in_n; index++) {
                    # 从静态数据结构中查找并获取64位整数,复制到输出指针位置
                    npy_uint64 v = npy_static_cdata.unpack_lookup_big[*inptr].uint64;
                    memcpy(outptr, &v, 8);
                    outptr += 8;
                    inptr += in_stride;
                }
            }
            else {
                # 按字节顺序(小端或者未指定顺序)循环处理输入数据
                for (index = 0; index < in_n; index++) {
                    npy_uint64 v = npy_static_cdata.unpack_lookup_big[*inptr].uint64;
                    # 如果顺序不是大端,进行字节交换
                    if (order != 'b') {
                        v = npy_bswap8(v);
                    }
                    memcpy(outptr, &v, 8);
                    outptr += 8;
                    inptr += in_stride;
                }
            }
            /* 清理尾部剩余部分 */
            if (in_tail) {
                npy_uint64 v = npy_static_cdata.unpack_lookup_big[*inptr].uint64;
                if (order != 'b') {
                    v = npy_bswap8(v);
                }
                memcpy(outptr, &v, in_tail);
            }
            /* 添加填充 */
            else if (out_pad) {
                memset(outptr, 0, out_pad);
            }
        }
        else {
            # 如果输出步长不为1
            if (order == 'b') {
                # 按字节顺序(大端)循环处理输入数据
                for (index = 0; index < in_n; index++) {
                    # 每个字节内的位处理
                    for (i = 0; i < 8; i++) {
                        *outptr = ((*inptr & (128 >> i)) != 0);
                        outptr += out_stride;
                    }
                    inptr += in_stride;
                }
                /* 清理尾部剩余部分 */
                for (i = 0; i < in_tail; i++) {
                    *outptr = ((*inptr & (128 >> i)) != 0);
                    outptr += out_stride;
                }
            }
            else {
                # 按字节顺序(小端或者未指定顺序)循环处理输入数据
                for (index = 0; index < in_n; index++) {
                    # 每个字节内的位处理
                    for (i = 0; i < 8; i++) {
                        *outptr = ((*inptr & (1 << i)) != 0);
                        outptr += out_stride;
                    }
                    inptr += in_stride;
                }
                /* 清理尾部剩余部分 */
                for (i = 0; i < in_tail; i++) {
                    *outptr = ((*inptr & (1 << i)) != 0);
                    outptr += out_stride;
                }
            }
            /* 添加填充 */
            for (index = 0; index < out_pad; index++) {
                *outptr = 0;
                outptr += out_stride;
            }
        }

        # 移动输入和输出迭代器到下一个位置
        PyArray_ITER_NEXT(it);
        PyArray_ITER_NEXT(ot);
    }
    # 结束多线程处理
    NPY_END_THREADS;

    # 释放迭代器对象
    Py_DECREF(it);
    Py_DECREF(ot);

    # 释放新创建的数组对象
    Py_DECREF(new);

    # 返回输出数组对象
    return (PyObject *)out;
fail:
    // 减少 new 指针的引用计数,处理异常情况
    Py_XDECREF(new);
    // 减少 out 指针的引用计数,处理异常情况
    Py_XDECREF(out);
    // 返回空指针,表示函数执行失败
    return NULL;
}


NPY_NO_EXPORT PyObject *
io_pack(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwds)
{
    PyObject *obj;                      // 输入的 Python 对象
    int axis = NPY_RAVEL_AXIS;          // 指定的轴,默认为展平
    static char *kwlist[] = {"in", "axis", "bitorder", NULL};  // 关键字参数列表
    char c = 'b';                       // 默认的字节顺序为 'b' (big-endian)
    const char * order_str = NULL;      // 指定的字节顺序字符串

    // 解析 Python 的参数元组和关键字参数
    if (!PyArg_ParseTupleAndKeywords( args, kwds, "O|O&s:pack" , kwlist,
                &obj, PyArray_AxisConverter, &axis, &order_str)) {
        // 解析失败时返回空指针
        return NULL;
    }

    // 如果指定了字节顺序字符串,则根据字符串设置字节顺序
    if (order_str != NULL) {
        if (strncmp(order_str, "little", 6) == 0)
            c = 'l';    // 如果字符串为 "little",设置为小端序
        else if (strncmp(order_str, "big", 3) == 0)
            c = 'b';    // 如果字符串为 "big",设置为大端序
        else {
            // 如果字符串既不是 "little" 也不是 "big",抛出数值错误异常
            PyErr_SetString(PyExc_ValueError,
                    "'order' must be either 'little' or 'big'");
            return NULL;
        }
    }

    // 调用 pack_bits 函数进行打包操作,并返回其结果
    return pack_bits(obj, axis, c);
}


NPY_NO_EXPORT PyObject *
io_unpack(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwds)
{
    PyObject *obj;                      // 输入的 Python 对象
    int axis = NPY_RAVEL_AXIS;          // 指定的轴,默认为展平
    PyObject *count = Py_None;          // 解包的位数
    static char *kwlist[] = {"in", "axis", "count", "bitorder", NULL};  // 关键字参数列表
    const char * c = NULL;              // 指定的字节顺序字符串

    // 解析 Python 的参数元组和关键字参数
    if (!PyArg_ParseTupleAndKeywords( args, kwds, "O|O&Os:unpack" , kwlist,
                &obj, PyArray_AxisConverter, &axis, &count, &c)) {
        // 解析失败时返回空指针
        return NULL;
    }

    // 如果没有指定字节顺序,则默认为 'b' (big-endian)
    if (c == NULL) {
        c = "b";
    }

    // 检查指定的字节顺序是否有效,必须以 'l' 或 'b' 开头
    if (c[0] != 'l' && c[0] != 'b') {
        // 如果不是有效的顺序,抛出数值错误异常
        PyErr_SetString(PyExc_ValueError,
                    "'order' must begin with 'l' or 'b'");
        return NULL;
    }

    // 调用 unpack_bits 函数进行解包操作,并返回其结果
    return unpack_bits(obj, axis, count, c[0]);
}

.\numpy\numpy\_core\src\multiarray\compiled_base.h

#ifndef NUMPY_CORE_SRC_MULTIARRAY_COMPILED_BASE_H_
#define NUMPY_CORE_SRC_MULTIARRAY_COMPILED_BASE_H_

#include "numpy/ndarraytypes.h"

// 声明不导出的函数arr_place,用于执行某种数组操作
NPY_NO_EXPORT PyObject *
arr_place(PyObject *, PyObject *, PyObject *);

// 声明不导出的函数arr_bincount,用于计算数组中每个值的出现次数
NPY_NO_EXPORT PyObject *
arr_bincount(PyObject *, PyObject *const *, Py_ssize_t, PyObject *);

// 声明不导出的函数arr__monotonicity,用于处理数组的单调性
NPY_NO_EXPORT PyObject *
arr__monotonicity(PyObject *, PyObject *, PyObject *kwds);

// 声明不导出的函数arr_interp,用于在数组上进行插值
NPY_NO_EXPORT PyObject *
arr_interp(PyObject *, PyObject *const *, Py_ssize_t, PyObject *, PyObject *);

// 声明不导出的函数arr_interp_complex,用于在复数数组上进行插值
NPY_NO_EXPORT PyObject *
arr_interp_complex(PyObject *, PyObject *const *, Py_ssize_t, PyObject *, PyObject *);

// 声明不导出的函数arr_ravel_multi_index,用于将多维数组索引展平为一维索引
NPY_NO_EXPORT PyObject *
arr_ravel_multi_index(PyObject *, PyObject *, PyObject *);

// 声明不导出的函数arr_unravel_index,用于将一维索引展开为多维数组索引
NPY_NO_EXPORT PyObject *
arr_unravel_index(PyObject *, PyObject *, PyObject *);

// 声明不导出的函数arr_add_docstring,用于给数组对象添加文档字符串
NPY_NO_EXPORT PyObject *
arr_add_docstring(PyObject *, PyObject *const *, Py_ssize_t);

// 声明不导出的函数io_pack,用于打包数据到某种格式
NPY_NO_EXPORT PyObject *
io_pack(PyObject *, PyObject *, PyObject *);

// 声明不导出的函数io_unpack,用于从某种格式解包数据
NPY_NO_EXPORT PyObject *
io_unpack(PyObject *, PyObject *, PyObject *);

#endif  /* NUMPY_CORE_SRC_MULTIARRAY_COMPILED_BASE_H_ */

.\numpy\numpy\_core\src\multiarray\conversion_utils.c

/*
 * 定义 NPY_NO_DEPRECATED_API 并设置为 NPY_API_VERSION
 * 定义 _MULTIARRAYMODULE
 */
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
#define _MULTIARRAYMODULE

/*
 * 引入必要的头文件和模块
 */
#include <Python.h>             // Python 标准头文件
#include <structmember.h>       // 结构成员相关的头文件

#include "numpy/arrayobject.h"      // NumPy 数组对象的头文件
#include "numpy/arrayscalars.h"     // NumPy 数组标量相关的头文件
#include "numpy/npy_math.h"         // NumPy 中的数学函数头文件

#include "npy_config.h"         // NumPy 配置文件

#include "common.h"             // 公共函数和宏定义的头文件
#include "arraytypes.h"         // 数组类型相关的头文件

#include "conversion_utils.h"   // 类型转换工具函数的头文件
#include "alloc.h"              // 内存分配相关的头文件
#include "npy_buffer.h"         // NumPy 缓冲区对象的头文件
#include "npy_static_data.h"    // NumPy 静态数据的头文件
#include "multiarraymodule.h"   // NumPy 多维数组模块的头文件

/*
 * 定义静态函数 PyArray_PyIntAsInt_ErrMsg
 * 用于将 PyObject 转换为 int,出错时打印错误消息
 */
static int
PyArray_PyIntAsInt_ErrMsg(PyObject *o, const char * msg) NPY_GCC_NONNULL(2);

/*
 * 定义静态函数 PyArray_PyIntAsIntp_ErrMsg
 * 用于将 PyObject 转换为 npy_intp,出错时打印错误消息
 */
static npy_intp
PyArray_PyIntAsIntp_ErrMsg(PyObject *o, const char * msg) NPY_GCC_NONNULL(2);

/****************************************************************
 * PyArg_ParseTuple 使用的转换函数
 ****************************************************************/

/*NUMPY_API
 *
 * PyArg_ParseTuple 中使用的转换函数,用于处理 O& 参数
 *
 * 如果传入的对象是数组类型,则直接返回该对象,并增加引用计数
 * 否则,尝试将对象转换为 NPY_ARRAY_CARRAY 类型的数组对象
 * 需要在使用 PyArray_Converter 后对返回的数组对象进行 DECREF
 */
NPY_NO_EXPORT int
PyArray_Converter(PyObject *object, PyObject **address)
{
    if (PyArray_Check(object)) {
        *address = object;
        Py_INCREF(object);
        return NPY_SUCCEED;
    }
    else {
        *address = PyArray_FROM_OF(object, NPY_ARRAY_CARRAY);
        if (*address == NULL) {
            return NPY_FAIL;
        }
        return NPY_SUCCEED;
    }
}

/*NUMPY_API
 * PyArg_ParseTuple 中使用的输出数组转换函数
 */
NPY_NO_EXPORT int
PyArray_OutputConverter(PyObject *object, PyArrayObject **address)
{
    if (object == NULL || object == Py_None) {
        *address = NULL;
        return NPY_SUCCEED;
    }
    if (PyArray_Check(object)) {
        *address = (PyArrayObject *)object;
        return NPY_SUCCEED;
    }
    else {
        PyErr_SetString(PyExc_TypeError,
                        "output must be an array");
        *address = NULL;
        return NPY_FAIL;
    }
}

/*
 * 将给定的值转换为整数,替代 PyArray_PyIntAsIntp,保留了旧版本的行为
 */
static inline npy_intp
dimension_from_scalar(PyObject *ob)
{
    npy_intp value = PyArray_PyIntAsIntp(ob);

    if (error_converting(value)) {
        if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
            PyErr_SetString(PyExc_ValueError,
                    "Maximum allowed dimension exceeded");
        }
        return -1;
    }
    return value;
}
/*NUMPY_API
 * 从序列中获取 intp 类型的块
 *
 * 此函数接受一个 Python 序列对象,并分配和填充一个 intp 数组以转换后的值。
 *
 * 在使用完毕后记得释放指针 seq.ptr,使用 PyDimMem_FREE(seq.ptr)**
 */
NPY_NO_EXPORT int
PyArray_IntpConverter(PyObject *obj, PyArray_Dims *seq)
{
    seq->ptr = NULL;  // 初始化指针为 NULL
    seq->len = 0;     // 初始化长度为 0

    /*
     * 当下面的弃用过期后,删除 `if` 语句,并更新 PyArray_OptionalIntpConverter 的注释。
     */
    if (obj == Py_None) {
        /* Numpy 1.20, 2020-05-31 */
        // 如果 obj 是 None,则发出弃用警告,并返回成功
        if (DEPRECATE(
                "Passing None into shape arguments as an alias for () is "
                "deprecated.") < 0){
            return NPY_FAIL;
        }
        return NPY_SUCCEED;
    }

    PyObject *seq_obj = NULL;

    /*
     * 如果 obj 是标量,则尽快跳转到 dimension_from_scalar,跳过所有无用的计算。
     */
    if (!PyLong_CheckExact(obj) && PySequence_Check(obj)) {
        // 如果 obj 不是精确的长整型且是序列,则快速获取序列对象
        seq_obj = PySequence_Fast(obj,
               "expected a sequence of integers or a single integer.");
        if (seq_obj == NULL) {
            /* 继续尝试解析为单个整数。 */
            PyErr_Clear();
        }
    }

    if (seq_obj == NULL) {
        /*
         * obj 可能是标量(如果 dimension_from_scalar 没有失败的话,在此刻还未执行检查以验证此假设)。
         */
        seq->ptr = npy_alloc_cache_dim(1);  // 分配大小为 1 的缓存维度
        if (seq->ptr == NULL) {
            PyErr_NoMemory();  // 内存分配失败的错误处理
            return NPY_FAIL;
        }
        else {
            seq->len = 1;  // 设置长度为 1

            seq->ptr[0] = dimension_from_scalar(obj);  // 将标量转换为维度值
            if (error_converting(seq->ptr[0])) {
                /*
                 * 如果发生的错误是类型错误(无法将值转换为整数),则告知用户预期的序列或整数。
                 */
                if (PyErr_ExceptionMatches(PyExc_TypeError)) {
                    PyErr_Format(PyExc_TypeError,
                            "expected a sequence of integers or a single "
                            "integer, got '%.100R'", obj);
                }
                npy_free_cache_dim_obj(*seq);  // 释放分配的缓存维度对象
                seq->ptr = NULL;  // 将指针置为 NULL
                return NPY_FAIL;
            }
        }
    }
    else {
        /*
         * `obj` is a sequence converted to the `PySequence_Fast` in `seq_obj`
         * `len` stores the size of the sequence `seq_obj`
         */
        Py_ssize_t len = PySequence_Fast_GET_SIZE(seq_obj);
        
        // Check if the length of the sequence exceeds the maximum supported dimensions
        if (len > NPY_MAXDIMS) {
            PyErr_Format(PyExc_ValueError,
                    "maximum supported dimension for an ndarray "
                    "is currently %d, found %d", NPY_MAXDIMS, len);
            Py_DECREF(seq_obj);
            return NPY_FAIL;
        }
        
        // Allocate memory for `seq->ptr` if the sequence length is greater than 0
        if (len > 0) {
            seq->ptr = npy_alloc_cache_dim(len);
            if (seq->ptr == NULL) {
                PyErr_NoMemory();
                Py_DECREF(seq_obj);
                return NPY_FAIL;
            }
        }

        // Set `seq->len` to the length of the sequence
        seq->len = len;

        // Convert Python index sequence `seq_obj` to C array `seq->ptr` of type `npy_intp`
        int nd = PyArray_IntpFromIndexSequence(seq_obj,
                (npy_intp *)seq->ptr, len);
        Py_DECREF(seq_obj);

        // Check if conversion was successful and dimensions match
        if (nd == -1 || nd != len) {
            // Free allocated memory and set `seq->ptr` to NULL on failure
            npy_free_cache_dim_obj(*seq);
            seq->ptr = NULL;
            return NPY_FAIL;
        }
    }

    // Return success status
    return NPY_SUCCEED;
/*
 * Like PyArray_IntpConverter, but leaves `seq` untouched if `None` is passed
 * rather than treating `None` as `()`.
 */
NPY_NO_EXPORT int
PyArray_OptionalIntpConverter(PyObject *obj, PyArray_Dims *seq)
{
    // 检查是否传入了 None 对象
    if (obj == Py_None) {
        // 如果是 None,直接返回成功,不做任何操作
        return NPY_SUCCEED;
    }

    // 否则调用 PyArray_IntpConverter 处理传入的对象
    return PyArray_IntpConverter(obj, seq);
}

NPY_NO_EXPORT int
PyArray_CopyConverter(PyObject *obj, NPY_COPYMODE *copymode) {
    // 检查是否传入了 None 对象
    if (obj == Py_None) {
        // 如果是 None,设置复制模式为 NPY_COPY_IF_NEEDED,并返回成功
        *copymode = NPY_COPY_IF_NEEDED;
        return NPY_SUCCEED;
    }

    int int_copymode;

    // 检查传入对象的类型是否为 _CopyMode
    if ((PyObject *)Py_TYPE(obj) == npy_static_pydata._CopyMode) {
        // 获取 _CopyMode 对象的 "value" 属性值
        PyObject* mode_value = PyObject_GetAttrString(obj, "value");
        if (mode_value == NULL) {
            return NPY_FAIL;
        }

        // 将属性值转换为整数
        int_copymode = (int)PyLong_AsLong(mode_value);
        Py_DECREF(mode_value);
        // 检查转换是否出错
        if (error_converting(int_copymode)) {
            return NPY_FAIL;
        }
    }
    else if(PyUnicode_Check(obj)) {
        // 如果传入对象是字符串,则返回错误,不允许用于 'copy' 关键字
        PyErr_SetString(PyExc_ValueError,
                        "strings are not allowed for 'copy' keyword. "
                        "Use True/False/None instead.");
        return NPY_FAIL;
    }
    else {
        // 对于其他对象,尝试使用 PyArray_BoolConverter 转换为布尔值
        npy_bool bool_copymode;
        if (!PyArray_BoolConverter(obj, &bool_copymode)) {
            return NPY_FAIL;
        }
        int_copymode = (int)bool_copymode;
    }

    // 设置复制模式,并返回成功
    *copymode = (NPY_COPYMODE)int_copymode;
    return NPY_SUCCEED;
}

NPY_NO_EXPORT int
PyArray_AsTypeCopyConverter(PyObject *obj, NPY_ASTYPECOPYMODE *copymode)
{
    int int_copymode;

    // 检查传入对象的类型是否为 _CopyMode
    if ((PyObject *)Py_TYPE(obj) == npy_static_pydata._CopyMode) {
        // 不允许使用 _CopyMode 枚举类型,返回错误
        PyErr_SetString(PyExc_ValueError,
                        "_CopyMode enum is not allowed for astype function. "
                        "Use true/false instead.");
        return NPY_FAIL;
    }
    else {
        // 否则,尝试使用 PyArray_BoolConverter 转换为布尔值
        npy_bool bool_copymode;
        if (!PyArray_BoolConverter(obj, &bool_copymode)) {
            return NPY_FAIL;
        }
        int_copymode = (int)bool_copymode;
    }

    // 设置复制模式,并返回成功
    *copymode = (NPY_ASTYPECOPYMODE)int_copymode;
    return NPY_SUCCEED;
}

/*NUMPY_API
 * Get buffer chunk from object
 *
 * this function takes a Python object which exposes the (single-segment)
 * buffer interface and returns a pointer to the data segment
 *
 * You should increment the reference count by one of buf->base
 * if you will hang on to a reference
 *
 * You only get a borrowed reference to the object. Do not free the
 * memory...
 */
NPY_NO_EXPORT int
PyArray_BufferConverter(PyObject *obj, PyArray_Chunk *buf)
{
    Py_buffer view;

    buf->ptr = NULL;
    buf->flags = NPY_ARRAY_BEHAVED;
    buf->base = NULL;
    // 检查是否传入了 None 对象
    if (obj == Py_None) {
        // 如果是 None,直接返回成功,不做任何操作
        return NPY_SUCCEED;
    }

    // 如果传入对象不是 None,则继续处理
    // (此处为示例中代码截断,未能提供完整的函数内容)
}
    /*
     * 如果无法获取对象的缓冲区视图,清除错误并标记缓冲区为不可写。
     * 然后再次尝试获取缓冲区视图,这次只要求连续且简单的缓冲区。
     */
    if (PyObject_GetBuffer(obj, &view,
                PyBUF_ANY_CONTIGUOUS|PyBUF_WRITABLE|PyBUF_SIMPLE) != 0) {
        PyErr_Clear();
        buf->flags &= ~NPY_ARRAY_WRITEABLE;
        if (PyObject_GetBuffer(obj, &view,
                PyBUF_ANY_CONTIGUOUS|PyBUF_SIMPLE) != 0) {
            return NPY_FAIL;
        }
    }

    /*
     * 将缓冲区视图的指针和长度分配给 buf 结构体。
     */
    buf->ptr = view.buf;
    buf->len = (npy_intp) view.len;

    /*
     * 在 Python 3 中,此段代码替换了被弃用的 PyObject_AsWriteBuffer 和
     * PyObject_AsReadBuffer 函数。这些函数释放了缓冲区。由提供缓冲区的对象
     * 负责在释放后保证缓冲区的有效性。
     */
    PyBuffer_Release(&view);

    /* 
     * 如果对象是内存视图类型,则将 buf 的 base 指向其基础对象。
     */
    if (PyMemoryView_Check(obj)) {
        buf->base = PyMemoryView_GET_BASE(obj);
    }
    /*
     * 如果 buf 的 base 仍然为空,则将其设置为当前对象。
     */
    if (buf->base == NULL) {
        buf->base = obj;
    }

    /*
     * 返回操作成功的标志。
     */
    return NPY_SUCCEED;
/*NUMPY_API
 * Get axis from an object (possibly None) -- a converter function,
 *
 * See also PyArray_ConvertMultiAxis, which also handles a tuple of axes.
 */
NPY_NO_EXPORT int
PyArray_AxisConverter(PyObject *obj, int *axis)
{
    // 如果对象是 None,则设置 axis 为 NPY_RAVEL_AXIS
    if (obj == Py_None) {
        *axis = NPY_RAVEL_AXIS;
    }
    // 否则,尝试将对象转换为整数作为 axis
    else {
        *axis = PyArray_PyIntAsInt_ErrMsg(obj,
                               "an integer is required for the axis");
        // 如果转换过程中出现错误,返回失败
        if (error_converting(*axis)) {
            return NPY_FAIL;
        }
    }
    // 返回成功
    return NPY_SUCCEED;
}

/*
 * Converts an axis parameter into an ndim-length C-array of
 * boolean flags, True for each axis specified.
 *
 * If obj is None or NULL, everything is set to True. If obj is a tuple,
 * each axis within the tuple is set to True. If obj is an integer,
 * just that axis is set to True.
 */
NPY_NO_EXPORT int
PyArray_ConvertMultiAxis(PyObject *axis_in, int ndim, npy_bool *out_axis_flags)
{
    /* None means all of the axes */
    // 如果 axis_in 是 None 或 NULL,则将所有轴设置为 True
    if (axis_in == Py_None || axis_in == NULL) {
        memset(out_axis_flags, 1, ndim);
        return NPY_SUCCEED;
    }
    /* A tuple of which axes */
    // 如果 axis_in 是一个元组,则根据元组中的每个轴设置对应位置为 True
    else if (PyTuple_Check(axis_in)) {
        int i, naxes;

        memset(out_axis_flags, 0, ndim);

        naxes = PyTuple_Size(axis_in);
        if (naxes < 0) {
            return NPY_FAIL;
        }
        // 遍历元组中的每个元素,将对应的轴设置为 True
        for (i = 0; i < naxes; ++i) {
            PyObject *tmp = PyTuple_GET_ITEM(axis_in, i);
            // 尝试将元组元素转换为整数轴
            int axis = PyArray_PyIntAsInt_ErrMsg(tmp,
                          "integers are required for the axis tuple elements");
            // 如果转换过程中出现错误,返回失败
            if (error_converting(axis)) {
                return NPY_FAIL;
            }
            // 检查和调整轴的有效性
            if (check_and_adjust_axis(&axis, ndim) < 0) {
                return NPY_FAIL;
            }
            // 检查是否有重复的轴值
            if (out_axis_flags[axis]) {
                PyErr_SetString(PyExc_ValueError,
                        "duplicate value in 'axis'");
                return NPY_FAIL;
            }
            // 将对应轴位置设置为 True
            out_axis_flags[axis] = 1;
        }

        return NPY_SUCCEED;
    }
    /* Try to interpret axis as an integer */
    // 否则,尝试将 axis_in 解释为一个整数轴
    else {
        int axis;

        memset(out_axis_flags, 0, ndim);

        // 尝试将 axis_in 转换为整数轴
        axis = PyArray_PyIntAsInt_ErrMsg(axis_in,
                                   "an integer is required for the axis");

        // 如果转换过程中出现错误,返回失败
        if (error_converting(axis)) {
            return NPY_FAIL;
        }
        /*
         * Special case letting axis={-1,0} slip through for scalars,
         * for backwards compatibility reasons.
         */
        // 对于零维数组(标量),允许 axis 取值为 {-1, 0},这是为了向后兼容
        if (ndim == 0 && (axis == 0 || axis == -1)) {
            return NPY_SUCCEED;
        }

        // 检查和调整轴的有效性
        if (check_and_adjust_axis(&axis, ndim) < 0) {
            return NPY_FAIL;
        }

        // 将对应轴位置设置为 True
        out_axis_flags[axis] = 1;

        return NPY_SUCCEED;
    }
}

/*NUMPY_API
 * Convert an object to true / false
 */
NPY_NO_EXPORT int
PyArray_BoolConverter(PyObject *object, npy_bool *val)
{
    // 将对象转换为布尔值
    if (PyObject_IsTrue(object)) {
        *val = NPY_TRUE;
    }
    else {
        *val = NPY_FALSE;
    }

        *val = NPY_FALSE;
    }
    // 返回成功
    return NPY_SUCCEED;
}
    // 检查是否有 Python 异常发生
    if (PyErr_Occurred()) {
        // 如果有异常发生,则返回失败标志
        return NPY_FAIL;
    }
    // 如果没有异常发生,则返回成功标志
    return NPY_SUCCEED;
}

/*
 * Optionally convert an object to true / false
 */
NPY_NO_EXPORT int
PyArray_OptionalBoolConverter(PyObject *object, int *val)
{
    /* Leave the desired default from the caller for Py_None */
    // 如果对象是 Py_None,则使用调用者指定的默认值
    if (object == Py_None) {
        return NPY_SUCCEED;
    }
    // 如果对象能被解释为 True,则将 *val 设置为 1
    if (PyObject_IsTrue(object)) {
        *val = 1;
    }
    else {
        // 否则将 *val 设置为 0
        *val = 0;
    }
    // 如果出现错误,返回 NPY_FAIL
    if (PyErr_Occurred()) {
        return NPY_FAIL;
    }
    // 操作成功,返回 NPY_SUCCEED
    return NPY_SUCCEED;
}

static int
string_converter_helper(
    PyObject *object,
    void *out,
    int (*str_func)(char const*, Py_ssize_t, void*),
    char const *name,
    char const *message)
{
    /* allow bytes for compatibility */
    // 允许 bytes 类型以保持兼容性
    PyObject *str_object = NULL;
    // 如果对象是 bytes 类型,则转换为 Unicode
    if (PyBytes_Check(object)) {
        str_object = PyUnicode_FromEncodedObject(object, NULL, NULL);
        // 转换失败,抛出 ValueError 异常
        if (str_object == NULL) {
            PyErr_Format(PyExc_ValueError,
                "%s %s (got %R)", name, message, object);
            return NPY_FAIL;
        }
    }
    // 如果对象是 Unicode 类型,直接使用
    else if (PyUnicode_Check(object)) {
        str_object = object;
        Py_INCREF(str_object);
    }
    else {
        // 其它类型抛出 TypeError 异常
        PyErr_Format(PyExc_TypeError,
            "%s must be str, not %s", name, Py_TYPE(object)->tp_name);
        return NPY_FAIL;
    }

    Py_ssize_t length;
    // 将 Unicode 对象转换为 UTF-8 编码的 C 字符串
    char const *str = PyUnicode_AsUTF8AndSize(str_object, &length);
    if (str == NULL) {
        Py_DECREF(str_object);
        return NPY_FAIL;
    }

    // 调用指定的 str_func 处理字符串
    int ret = str_func(str, length, out);
    Py_DECREF(str_object);
    // 如果 str_func 返回负数且未设置异常,则抛出 ValueError 异常
    if (ret < 0) {
        if (!PyErr_Occurred()) {
            PyErr_Format(PyExc_ValueError,
                "%s %s (got %R)", name, message, object);
        }
        return NPY_FAIL;
    }
    // 操作成功,返回 NPY_SUCCEED
    return NPY_SUCCEED;
}

static int byteorder_parser(char const *str, Py_ssize_t length, void *data)
{
    char *endian = (char *)data;

    // 如果字符串长度小于 1,返回 -1
    if (length < 1) {
        return -1;
    }
    // 解析字节顺序字符
    else if (str[0] == NPY_BIG || str[0] == NPY_LITTLE ||
             str[0] == NPY_NATIVE || str[0] == NPY_IGNORE) {
        *endian = str[0];
        return 0;
    }
    else if (str[0] == 'b' || str[0] == 'B') {
        *endian = NPY_BIG;
        return 0;
    }
    else if (str[0] == 'l' || str[0] == 'L') {
        *endian = NPY_LITTLE;
        return 0;
    }
    else if (str[0] == 'n' || str[0] == 'N') {
        *endian = NPY_NATIVE;
        return 0;
    }
    else if (str[0] == 'i' || str[0] == 'I') {
        *endian = NPY_IGNORE;
        return 0;
    }
    else if (str[0] == 's' || str[0] == 'S') {
        *endian = NPY_SWAP;
        return 0;
    }
    else {
        // 未识别的字符,返回 -1
        return -1;
    }
}

/*NUMPY_API
 * Convert object to endian
 */
NPY_NO_EXPORT int
PyArray_ByteorderConverter(PyObject *obj, char *endian)
{
    // 调用通用字符串转换函数处理字节顺序
    return string_converter_helper(
        obj, (void *)endian, byteorder_parser, "byteorder", "not recognized");
}

static int sortkind_parser(char const *str, Py_ssize_t length, void *data)
{
    # 将 void 指针类型的 data 强制转换为 NPY_SORTKIND 指针类型,并赋值给 sortkind
    NPY_SORTKIND *sortkind = (NPY_SORTKIND *)data;

    # 如果 length 小于 1,返回错误码 -1
    if (length < 1) {
        return -1;
    }

    # 如果 str 的第一个字符是 'q' 或 'Q',设置 sortkind 为 NPY_QUICKSORT,返回成功码 0
    if (str[0] == 'q' || str[0] == 'Q') {
        *sortkind = NPY_QUICKSORT;
        return 0;
    }
    # 如果 str 的第一个字符是 'h' 或 'H',设置 sortkind 为 NPY_HEAPSORT,返回成功码 0
    else if (str[0] == 'h' || str[0] == 'H') {
        *sortkind = NPY_HEAPSORT;
        return 0;
    }
    # 如果 str 的第一个字符是 'm' 或 'M',设置 sortkind 为 NPY_MERGESORT,返回成功码 0
    else if (str[0] == 'm' || str[0] == 'M') {
        /*
         * Mergesort 是 NPY_STABLESORT 的别名。
         * 这样做保持了向后兼容性,同时允许使用其他类型的稳定排序。
         */
        *sortkind = NPY_MERGESORT;
        return 0;
    }
    # 如果 str 的第一个字符是 's' 或 'S',设置 sortkind 为 NPY_STABLESORT,返回成功码 0
    else if (str[0] == 's' || str[0] == 'S') {
        /*
         * NPY_STABLESORT 是以下之一:
         *
         *   - mergesort
         *   - timsort
         *
         * 具体使用哪种取决于数据类型。
         */
        *sortkind = NPY_STABLESORT;
        return 0;
    }
    # 如果 str 的第一个字符不符合上述任何条件,返回错误码 -1
    else {
        return -1;
    }
/*NUMPY_API
 * Convert object to sort kind
 */
NPY_NO_EXPORT int
PyArray_SortkindConverter(PyObject *obj, NPY_SORTKIND *sortkind)
{
    /* Leave the desired default from the caller for Py_None */
    if (obj == Py_None) {
        return NPY_SUCCEED;
    }
    /* 使用帮助函数进行字符串转换,将结果保存到 sortkind 指针所指向的位置 */
    return string_converter_helper(
        obj, (void *)sortkind, sortkind_parser, "sort kind",
        "must be one of 'quick', 'heap', or 'stable'");
}

/* 定义 selectkind_parser 函数,用于解析选择类型的字符串 */
static int selectkind_parser(char const *str, Py_ssize_t length, void *data)
{
    NPY_SELECTKIND *selectkind = (NPY_SELECTKIND *)data;

    if (length == 11 && strcmp(str, "introselect") == 0) {
        *selectkind = NPY_INTROSELECT;
        return 0;
    }
    else {
        return -1;
    }
}

/*NUMPY_API
 * Convert object to select kind
 */
NPY_NO_EXPORT int
PyArray_SelectkindConverter(PyObject *obj, NPY_SELECTKIND *selectkind)
{
    /* 使用帮助函数进行字符串转换,将结果保存到 selectkind 指针所指向的位置 */
    return string_converter_helper(
        obj, (void *)selectkind, selectkind_parser, "select kind",
        "must be 'introselect'");
}

/* 定义 searchside_parser 函数,用于解析搜索方向的字符串 */
static int searchside_parser(char const *str, Py_ssize_t length, void *data)
{
    NPY_SEARCHSIDE *side = (NPY_SEARCHSIDE *)data;
    int is_exact = 0;

    if (length < 1) {
        return -1;
    }
    else if (str[0] == 'l' || str[0] == 'L') {
        *side = NPY_SEARCHLEFT;
        is_exact = (length == 4 && strcmp(str, "left") == 0);
    }
    else if (str[0] == 'r' || str[0] == 'R') {
        *side = NPY_SEARCHRIGHT;
        is_exact = (length == 5 && strcmp(str, "right") == 0);
    }
    else {
        return -1;
    }

    /* 如果不是精确匹配,产生 DeprecationWarning */
    if (!is_exact) {
        /* NumPy 1.20, 2020-05-19 */
        if (DEPRECATE("inexact matches and case insensitive matches "
                      "for search side are deprecated, please use "
                      "one of 'left' or 'right' instead.") < 0) {
            return -1;
        }
    }

    return 0;
}

/*NUMPY_API
 * Convert object to searchsorted side
 */
NPY_NO_EXPORT int
PyArray_SearchsideConverter(PyObject *obj, void *addr)
{
    /* 使用帮助函数进行字符串转换,将结果保存到 addr 所指向的位置 */
    return string_converter_helper(
        obj, addr, searchside_parser, "search side",
        "must be 'left' or 'right'");
}

/* 定义 order_parser 函数,用于解析数组排序顺序的字符串 */
static int order_parser(char const *str, Py_ssize_t length, void *data)
{
    NPY_ORDER *val = (NPY_ORDER *)data;
    if (length != 1) {
        return -1;
    }
    if (str[0] == 'C' || str[0] == 'c') {
        *val = NPY_CORDER;
        return 0;
    }
    else if (str[0] == 'F' || str[0] == 'f') {
        *val = NPY_FORTRANORDER;
        return 0;
    }
    else if (str[0] == 'A' || str[0] == 'a') {
        *val = NPY_ANYORDER;
        return 0;
    }
    else if (str[0] == 'K' || str[0] == 'k') {
        *val = NPY_KEEPORDER;
        return 0;
    }
    else {
        return -1;
    }
}

/*NUMPY_API
 * Convert an object to FORTRAN / C / ANY / KEEP
 */
NPY_NO_EXPORT int
PyArray_OrderConverter(PyObject *object, NPY_ORDER *val)
{
    /* 如果 object 是 Py_None,则使用调用者期望的默认值 */
    if (object == Py_None) {
        // 如果 object 是 Py_None,则直接返回成功
        return NPY_SUCCEED;
    }
    // 否则,调用字符串转换助手函数,将 object 转换为字符串,并存储到 val 中
    return string_converter_helper(
        object, (void *)val, order_parser, "order",
        "must be one of 'C', 'F', 'A', or 'K'");
}

/* 解析剪裁模式字符串并转换为枚举值 */
static int clipmode_parser(char const *str, Py_ssize_t length, void *data)
{
    NPY_CLIPMODE *val = (NPY_CLIPMODE *)data;
    int is_exact = 0;

    // 检查字符串长度,如果小于1则返回错误
    if (length < 1) {
        return -1;
    }

    // 根据字符串首字符确定剪裁模式
    if (str[0] == 'C' || str[0] == 'c') {
        *val = NPY_CLIP;
        is_exact = (length == 4 && strcmp(str, "clip") == 0);  // 检查是否精确匹配
    }
    else if (str[0] == 'W' || str[0] == 'w') {
        *val = NPY_WRAP;
        is_exact = (length == 4 && strcmp(str, "wrap") == 0);  // 检查是否精确匹配
    }
    else if (str[0] == 'R' || str[0] == 'r') {
        *val = NPY_RAISE;
        is_exact = (length == 5 && strcmp(str, "raise") == 0);  // 检查是否精确匹配
    }
    else {
        return -1;  // 如果首字符不符合预期,则返回错误
    }

    /* 过滤掉大小写不敏感或非精确匹配的输入,并输出 DeprecationWarning */
    if (!is_exact) {
        /* Numpy 1.20, 2020-05-19 */
        if (DEPRECATE("inexact matches and case insensitive matches "
                      "for clip mode are deprecated, please use "
                      "one of 'clip', 'raise', or 'wrap' instead.") < 0) {
            return -1;
        }
    }

    return 0;  // 解析成功返回 0
}

/*NUMPY_API
 * 将对象转换为 NPY_RAISE / NPY_CLIP / NPY_WRAP
 */
NPY_NO_EXPORT int
PyArray_ClipmodeConverter(PyObject *object, NPY_CLIPMODE *val)
{
    // 如果对象为空或为 None,则设置为 NPY_RAISE
    if (object == NULL || object == Py_None) {
        *val = NPY_RAISE;
    }

    // 如果对象是字节串或 Unicode 字符串,则调用字符串转换器助手函数进行处理
    else if (PyBytes_Check(object) || PyUnicode_Check(object)) {
        return string_converter_helper(
            object, (void *)val, clipmode_parser, "clipmode",
            "must be one of 'clip', 'raise', or 'wrap'");
    }
    else {
        /* 对于传递了 `RAISE`, `WRAP`, `CLIP` 的用户 */
        int number = PyArray_PyIntAsInt(object);
        if (error_converting(number)) {
            goto fail;
        }
        if (number <= (int) NPY_RAISE
                && number >= (int) NPY_CLIP) {
            *val = (NPY_CLIPMODE) number;
        }
        else {
            PyErr_Format(PyExc_ValueError,
                    "integer clipmode must be RAISE, WRAP, or CLIP "
                    "from 'numpy._core.multiarray'");
        }
    }
    return NPY_SUCCEED;

 fail:
    PyErr_SetString(PyExc_TypeError,
                    "clipmode not understood");
    return NPY_FAIL;
}

/*NUMPY_API
 * 将对象转换为包含 n 个 NPY_CLIPMODE 值的数组。
 * 这用于需要为每个轴应用不同模式的函数,如 ravel_multi_index。
 */
NPY_NO_EXPORT int
PyArray_ConvertClipmodeSequence(PyObject *object, NPY_CLIPMODE *modes, int n)
{
    int i;
    /* 获取剪裁模式(s) */
    // 检查对象是否存在且为元组或列表
    if (object && (PyTuple_Check(object) || PyList_Check(object))) {
        // 如果对象是序列且长度不等于 n,则抛出长度错误异常并返回失败
        if (PySequence_Size(object) != n) {
            PyErr_Format(PyExc_ValueError,
                    "list of clipmodes has wrong length (%zd instead of %d)",
                    PySequence_Size(object), n);
            return NPY_FAIL;
        }

        // 遍历对象的每个元素
        for (i = 0; i < n; ++i) {
            // 获取序列中的第 i 个元素
            PyObject *item = PySequence_GetItem(object, i);
            // 如果获取元素失败,则返回失败
            if(item == NULL) {
                return NPY_FAIL;
            }

            // 尝试将元素转换为数组剪裁模式,若转换失败则释放元素并返回失败
            if(PyArray_ClipmodeConverter(item, &modes[i]) != NPY_SUCCEED) {
                Py_DECREF(item);
                return NPY_FAIL;
            }

            // 释放元素引用
            Py_DECREF(item);
        }
    }
    // 如果对象不是序列,尝试将其作为单个剪裁模式处理
    else if (PyArray_ClipmodeConverter(object, &modes[0]) == NPY_SUCCEED) {
        // 如果成功转换为剪裁模式,则将该模式应用到所有 modes 数组元素中
        for (i = 1; i < n; ++i) {
            modes[i] = modes[0];
        }
    }
    // 如果对象既不是序列也无法转换为剪裁模式,则返回失败
    else {
        return NPY_FAIL;
    }
    // 若所有操作成功完成,则返回成功
    return NPY_SUCCEED;
/* 
 * Parse and interpret a string representation of correlation mode
 * to an NPY_CORRELATEMODE value.
 */
static int correlatemode_parser(char const *str, Py_ssize_t length, void *data)
{
    NPY_CORRELATEMODE *val = (NPY_CORRELATEMODE *)data;
    int is_exact = 0;

    // Ensure the input string is not empty
    if (length < 1) {
        return -1;
    }

    // Check for case-insensitive matching for 'valid'
    if (str[0] == 'V' || str[0] == 'v') {
        *val = NPY_VALID;
        is_exact = (length == 5 && strcmp(str, "valid") == 0);
    }
    // Check for case-insensitive matching for 'same'
    else if (str[0] == 'S' || str[0] == 's') {
        *val = NPY_SAME;
        is_exact = (length == 4 && strcmp(str, "same") == 0);
    }
    // Check for case-insensitive matching for 'full'
    else if (str[0] == 'F' || str[0] == 'f') {
        *val = NPY_FULL;
        is_exact = (length == 4 && strcmp(str, "full") == 0);
    }
    else {
        // Invalid mode string
        return -1;
    }

    /* 
     * If the match was not exact (case-sensitive),
     * issue a deprecation warning.
     */
    if (!is_exact) {
        /* Numpy 1.21, 2021-01-19 */
        // Issue a deprecation warning for inexact matches
        if (DEPRECATE("inexact matches and case insensitive matches for "
                      "convolve/correlate mode are deprecated, please "
                      "use one of 'valid', 'same', or 'full' instead.") < 0) {
            return -1;
        }
    }

    // Parsing successful
    return 0;
}

/*
 * Convert an object to NPY_VALID / NPY_SAME / NPY_FULL
 */
NPY_NO_EXPORT int
PyArray_CorrelatemodeConverter(PyObject *object, NPY_CORRELATEMODE *val)
{
    // Check if the object is a Unicode string
    if (PyUnicode_Check(object)) {
        // Use string_converter_helper to convert the Unicode object
        return string_converter_helper(
            object, (void *)val, correlatemode_parser, "mode",
            "must be one of 'valid', 'same', or 'full'");
    }

    // If the object is not a Unicode string
    else {
        // Attempt conversion assuming it's an integer
        int number = PyArray_PyIntAsInt(object);
        // Handle conversion errors
        if (error_converting(number)) {
            PyErr_SetString(PyExc_TypeError,
                            "convolve/correlate mode not understood");
            return NPY_FAIL;
        }
        // Check if the integer is within the valid range for modes
        if (number <= (int) NPY_FULL && number >= (int) NPY_VALID) {
            *val = (NPY_CORRELATEMODE) number;
            return NPY_SUCCEED;
        }
        else {
            // Invalid integer mode value
            PyErr_Format(PyExc_ValueError,
                         "integer convolve/correlate mode must be 0, 1, or 2");
            return NPY_FAIL;
        }
    }
}
    # 当输入的 case 是 's' 时执行以下代码块
    case 's':
        # 如果输入长度为 6 并且字符串与 "unsafe" 完全相同
        if (length == 6 && strcmp(str, "unsafe") == 0) {
            # 设置 *casting 指针指向的值为 NPY_UNSAFE_CASTING
            *casting = NPY_UNSAFE_CASTING;
            # 返回 0 表示成功匹配并设置
            return 0;
        }
        # 如果条件不满足则跳出 switch 结构
        break;
    }
    # 默认情况返回 -1,表示未找到匹配项
    return -1;
/*NUMPY_API
 * 将任何 Python 对象 *obj* 转换为一个 NPY_CASTING 枚举。
 */
NPY_NO_EXPORT int
PyArray_CastingConverter(PyObject *obj, NPY_CASTING *casting)
{
    // 调用辅助函数进行字符串转换
    return string_converter_helper(
        obj, (void *)casting, casting_parser, "casting",
            "must be one of 'no', 'equiv', 'safe', "
            "'same_kind', or 'unsafe'");
    // 返回 0 表示成功
    return 0;
}

/*****************************
* 其他转换函数
*****************************/

static int
PyArray_PyIntAsInt_ErrMsg(PyObject *o, const char * msg)
{
    npy_intp long_value;
    /* 这里假设 NPY_SIZEOF_INTP >= NPY_SIZEOF_INT */
    long_value = PyArray_PyIntAsIntp_ErrMsg(o, msg);

#if (NPY_SIZEOF_INTP > NPY_SIZEOF_INT)
    // 如果 long_value 超出 int 的范围,则抛出 ValueError
    if ((long_value < INT_MIN) || (long_value > INT_MAX)) {
        PyErr_SetString(PyExc_ValueError, "integer won't fit into a C int");
        return -1;
    }
#endif
    // 返回 long_value 强制转换为 int 类型
    return (int) long_value;
}

/*NUMPY_API*/
NPY_NO_EXPORT int
PyArray_PyIntAsInt(PyObject *o)
{
    // 调用带错误消息的 PyArray_PyIntAsInt_ErrMsg 函数
    return PyArray_PyIntAsInt_ErrMsg(o, "an integer is required");
}

static npy_intp
PyArray_PyIntAsIntp_ErrMsg(PyObject *o, const char * msg)
{
#if (NPY_SIZEOF_LONG < NPY_SIZEOF_INTP)
    long long long_value = -1;
#else
    long long_value = -1;
#endif
    PyObject *obj, *err;

    /*
     * 更加严格,不允许 bool 值。
     * np.bool 也被禁止,因为布尔数组目前不支持索引。
     */
    // 如果 o 为空或者是 bool 值,或者是布尔类型数组,则抛出 TypeError
    if (!o || PyBool_Check(o) || PyArray_IsScalar(o, Bool)) {
        PyErr_SetString(PyExc_TypeError, msg);
        return -1;
    }

    /*
     * 因为这是通常的情况,首先检查 o 是否是整数。这是一个精确的检查,因为否则会使用 __index__ 方法。
     */
    // 如果 o 是 PyLong_CheckExact,则直接将其转换为 long_value
    if (PyLong_CheckExact(o)) {
#if (NPY_SIZEOF_LONG < NPY_SIZEOF_INTP)
        long_value = PyLong_AsLongLong(o);
#else
        long_value = PyLong_AsLong(o);
#endif
        return (npy_intp)long_value;
    }

    /*
     * 最一般的情况。PyNumber_Index(o) 包含了所有情况,包括数组。原则上,可以在停用后使用 PyIndex_AsSSize_t 替换整个函数。
     */
    // 调用 PyNumber_Index(o) 获取索引,然后将其转换为 long_value
    obj = PyNumber_Index(o);
    if (obj == NULL) {
        return -1;
    }
#if (NPY_SIZEOF_LONG < NPY_SIZEOF_INTP)
    long_value = PyLong_AsLongLong(obj);
#else
    long_value = PyLong_AsLong(obj);
#endif
    Py_DECREF(obj);

    // 如果转换失败,则设置相应错误消息
    if (error_converting(long_value)) {
        err = PyErr_Occurred();
        // 只在这里替换 TypeError,因为这是正常的错误情况。
        if (PyErr_GivenExceptionMatches(err, PyExc_TypeError)) {
            PyErr_SetString(PyExc_TypeError, msg);
        }
        return -1;
    }
    // 转换成功后检查溢出情况
    goto overflow_check; /* 防止未使用的警告 */

overflow_check:
#if (NPY_SIZEOF_LONG < NPY_SIZEOF_INTP)
  #if (NPY_SIZEOF_LONGLONG > NPY_SIZEOF_INTP)
    // 检查 long_value 是否超出 numpy.intp 类型的范围
    if ((long_value < NPY_MIN_INTP) || (long_value > NPY_MAX_INTP)) {
        // 如果超出范围,设置 OverflowError 异常并返回错误码 -1
        PyErr_SetString(PyExc_OverflowError,
                "Python int too large to convert to C numpy.intp");
        return -1;
    }
  #endif
#else
  #if (NPY_SIZEOF_LONG > NPY_SIZEOF_INTP)
    // 如果长整型的大小大于 npy_intp 的大小,则检查 long_value 是否超出 npy_intp 的范围
    if ((long_value < NPY_MIN_INTP) || (long_value > NPY_MAX_INTP)) {
        // 如果 long_value 超出范围,设置 OverflowError 并返回 -1
        PyErr_SetString(PyExc_OverflowError,
                "Python int too large to convert to C numpy.intp");
        return -1;
    }
  #endif
#endif
    // 返回 long_value
    return long_value;
}

/*NUMPY_API*/
// 将 Python 中的整数对象 o 转换为 npy_intp 类型
NPY_NO_EXPORT npy_intp
PyArray_PyIntAsIntp(PyObject *o)
{
    // 调用带错误消息的 PyArray_PyIntAsIntp_ErrMsg 函数
    return PyArray_PyIntAsIntp_ErrMsg(o, "an integer is required");
}


NPY_NO_EXPORT int
// 将 Python 对象 o 转换为 npy_intp 类型的 C 数组指针 *val
PyArray_IntpFromPyIntConverter(PyObject *o, npy_intp *val)
{
    // 调用 PyArray_PyIntAsIntp 将 o 转换为 npy_intp 类型,并将结果赋给 *val
    *val = PyArray_PyIntAsIntp(o);
    // 如果转换出错,返回 NPY_FAIL
    if (error_converting(*val)) {
        return NPY_FAIL;
    }
    // 成功转换,返回 NPY_SUCCEED
    return NPY_SUCCEED;
}


/**
 * 从整数序列中读取值并存储到数组中。
 *
 * @param  seq      使用 `PySequence_Fast` 创建的序列。
 * @param  vals     用于存储维度的数组(必须足够大以容纳 `maxvals` 个值)。
 * @param  max_vals 可以写入 `vals` 的最大维度数。
 * @return          维度数或如果发生错误则返回 -1。
 *
 * .. note::
 *
 *   与 PyArray_IntpFromSequence 相反,它使用并返回 `npy_intp`
 *      作为值的数量。
 */
NPY_NO_EXPORT npy_intp
PyArray_IntpFromIndexSequence(PyObject *seq, npy_intp *vals, npy_intp maxvals)
{
    /*
     * 首先,检查序列是否是标量整数或是否可以“转换”为标量。
     */
    Py_ssize_t nd = PySequence_Fast_GET_SIZE(seq);
    PyObject *op;
    for (Py_ssize_t i = 0; i < PyArray_MIN(nd, maxvals); i++) {
        op = PySequence_Fast_GET_ITEM(seq, i);

        // 调用 dimension_from_scalar 获取标量 op 的维度,并存储到 vals[i] 中
        vals[i] = dimension_from_scalar(op);
        // 如果转换出错,返回 -1
        if (error_converting(vals[i])) {
            return -1;
        }
    }
    // 返回维度数 nd
    return nd;
}

/*NUMPY_API
 * PyArray_IntpFromSequence
 * 返回转换的整数数目或如果发生错误则返回 -1。
 * vals 必须足够大以容纳 maxvals
 */
NPY_NO_EXPORT int
// 从 Python 对象 seq 转换为 npy_intp 数组 vals
PyArray_IntpFromSequence(PyObject *seq, npy_intp *vals, int maxvals)
{
    PyObject *seq_obj = NULL;
    // 如果 seq 不是长整数并且是序列类型
    if (!PyLong_CheckExact(seq) && PySequence_Check(seq)) {
        // 使用 PySequence_Fast 尝试快速获取序列对象 seq_obj
        seq_obj = PySequence_Fast(seq,
            "expected a sequence of integers or a single integer");
        // 如果获取失败,继续尝试作为单个整数解析
        if (seq_obj == NULL) {
            PyErr_Clear();
        }
    }

    // 如果 seq_obj 为空
    if (seq_obj == NULL) {
        // 将 seq 视为标量,并将其维度存储到 vals[0] 中
        vals[0] = dimension_from_scalar(seq);
        // 如果转换出错,抛出适当的 TypeError 异常
        if (error_converting(vals[0])) {
            if (PyErr_ExceptionMatches(PyExc_TypeError)) {
                PyErr_Format(PyExc_TypeError,
                        "expected a sequence of integers or a single "
                        "integer, got '%.100R'", seq);
            }
            return -1;
        }
        // 返回 1 表示成功转换一个值
        return 1;
    }
    else {
        int res;
        // 调用 PyArray_IntpFromIndexSequence 从 seq_obj 中获取 npy_intp 类型的值到 vals,并最多获取 maxvals 个值
        res = PyArray_IntpFromIndexSequence(seq_obj, vals, (npy_intp)maxvals);
        // 释放 seq_obj 对象的引用
        Py_DECREF(seq_obj);
        // 返回转换结果
        return res;
    }
}
/**
 * WARNING: This flag is a bad idea, but was the only way to both
 *   1) Support unpickling legacy pickles with object types.
 *   2) Deprecate (and later disable) usage of O4 and O8
 *
 * The key problem is that the pickled representation unpickles by
 * directly calling the dtype constructor, which has no way of knowing
 * that it is in an unpickle context instead of a normal context without
 * evil global state like we create here.
 */
NPY_NO_EXPORT NPY_TLS int evil_global_disable_warn_O4O8_flag = 0;

/*
 * Convert a gentype (that is actually a generic kind character) and
 * it's itemsize to a NUmPy typenumber, i.e. `itemsize=4` and `gentype='f'`
 * becomes `NPY_FLOAT32`.
 */
NPY_NO_EXPORT int
PyArray_TypestrConvert(int itemsize, int gentype)
{
    int newtype = NPY_NOTYPE;

    switch (gentype) {
        case NPY_GENBOOLLTR:
            if (itemsize == 1) {
                newtype = NPY_BOOL;
            }
            break;

        case NPY_SIGNEDLTR:
            switch(itemsize) {
                case 1:
                    newtype = NPY_INT8;
                    break;
                case 2:
                    newtype = NPY_INT16;
                    break;
                case 4:
                    newtype = NPY_INT32;
                    break;
                case 8:
                    newtype = NPY_INT64;
                    break;
#ifdef NPY_INT128
                case 16:
                    newtype = NPY_INT128;
                    break;
#endif
            }
            break;

        case NPY_UNSIGNEDLTR:
            switch(itemsize) {
                case 1:
                    newtype = NPY_UINT8;
                    break;
                case 2:
                    newtype = NPY_UINT16;
                    break;
                case 4:
                    newtype = NPY_UINT32;
                    break;
                case 8:
                    newtype = NPY_UINT64;
                    break;
#ifdef NPY_INT128
                case 16:
                    newtype = NPY_UINT128;
                    break;
#endif
            }
            break;

        case NPY_FLOATINGLTR:
            switch(itemsize) {
                case 2:
                    newtype = NPY_FLOAT16;
                    break;
                case 4:
                    newtype = NPY_FLOAT32;
                    break;
                case 8:
                    newtype = NPY_FLOAT64;
                    break;
#ifdef NPY_FLOAT80
                case 10:
                    newtype = NPY_FLOAT80;
                    break;
#endif
#ifdef NPY_FLOAT96
                case 12:
                    newtype = NPY_FLOAT96;
                    break;
#endif
#ifdef NPY_FLOAT128
                case 16:
                    newtype = NPY_FLOAT128;
                    break;
#endif
            }
            break;
    }

    // 返回对应的 NumPy 类型编号
    return newtype;
}
#endif
            }
            break;

        case NPY_COMPLEXLTR:
            switch(itemsize) {
                case 8:
                    // 设置新类型为复数类型 NPY_COMPLEX64
                    newtype = NPY_COMPLEX64;
                    break;
                case 16:
                    // 设置新类型为复数类型 NPY_COMPLEX128
                    newtype = NPY_COMPLEX128;
                    break;
#ifdef NPY_FLOAT80
                case 20:
                    // 设置新类型为复数类型 NPY_COMPLEX160(仅在 NPY_FLOAT80 定义时有效)
                    newtype = NPY_COMPLEX160;
                    break;
#endif
#ifdef NPY_FLOAT96
                case 24:
                    // 设置新类型为复数类型 NPY_COMPLEX192(仅在 NPY_FLOAT96 定义时有效)
                    newtype = NPY_COMPLEX192;
                    break;
#endif
#ifdef NPY_FLOAT128
                case 32:
                    // 设置新类型为复数类型 NPY_COMPLEX256(仅在 NPY_FLOAT128 定义时有效)
                    newtype = NPY_COMPLEX256;
                    break;
#endif
            }
            break;

        case NPY_OBJECTLTR:
            /*
             * 对于 'O4' 和 'O8',允许通过,但会发出废弃警告。
             * 对于所有其他情况,通过不设置 newtype 来引发异常。
             */
            if (itemsize == 4 || itemsize == 8) {
                int ret = 0;
                if (evil_global_disable_warn_O4O8_flag) {
                    /* 2012-02-04, 1.7, 不确定何时可以移除此代码 */
                    // 发出废弃警告,提示使用 'O' 替代 'O4' 和 'O8'
                    ret = DEPRECATE("DType strings 'O4' and 'O8' are "
                            "deprecated because they are platform "
                            "specific. Use 'O' instead");
                }

                if (ret == 0) {
                    // 设置新类型为对象类型 NPY_OBJECT
                    newtype = NPY_OBJECT;
                }
            }
            break;

        case NPY_STRINGLTR:
            // 设置新类型为字符串类型 NPY_STRING
            newtype = NPY_STRING;
            break;

        case NPY_DEPRECATED_STRINGLTR2:
        {
            /*
             * 发出废弃警告,可能会引发异常,如果警告被配置为错误,不设置 newtype。
             */
            // 发出废弃警告,提示在 NumPy 2.0 中 'a' 数据类型别名已被废弃,使用 'S' 别名替代
            int ret = DEPRECATE("Data type alias 'a' was deprecated in NumPy 2.0. "
                                "Use the 'S' alias instead.");
            if (ret == 0) {
                // 设置新类型为字符串类型 NPY_STRING
                newtype = NPY_STRING;
            }
            break;
        }
        case NPY_UNICODELTR:
            // 设置新类型为Unicode类型 NPY_UNICODE
            newtype = NPY_UNICODE;
            break;

        case NPY_VOIDLTR:
            // 设置新类型为VOID类型 NPY_VOID
            newtype = NPY_VOID;
            break;

        case NPY_DATETIMELTR:
            if (itemsize == 8) {
                // 设置新类型为日期时间类型 NPY_DATETIME
                newtype = NPY_DATETIME;
            }
            break;

        case NPY_TIMEDELTALTR:
            if (itemsize == 8) {
                // 设置新类型为时间间隔类型 NPY_TIMEDELTA
                newtype = NPY_TIMEDELTA;
            }
            break;
    }

    // 返回确定的新数据类型
    return newtype;
}

/* Lifted from numarray */
/* TODO: not documented */
/*NUMPY_API
  PyArray_IntTupleFromIntp
*/
NPY_NO_EXPORT PyObject *
PyArray_IntTupleFromIntp(int len, npy_intp const *vals)
{
    int i;
    // 创建一个包含整数的元组对象
    PyObject *intTuple = PyTuple_New(len);

    if (!intTuple) {
        // 如果创建失败,跳转到失败处理分支
        goto fail;
    }
    // 循环遍历 vals 数组,逐个处理数组元素
    for (i = 0; i < len; i++) {
        // 根据 vals[i] 创建一个 Python int 对象
        PyObject *o = PyArray_PyIntFromIntp(vals[i]);
        // 如果创建失败,则执行失败处理逻辑
        if (!o) {
            // 释放已创建的 intTuple 对象
            Py_DECREF(intTuple);
            intTuple = NULL;
            // 跳转到失败处理标签
            goto fail;
        }
        // 将创建的 int 对象 o 放入 intTuple 元组的第 i 个位置
        PyTuple_SET_ITEM(intTuple, i, o);
    }

 fail:
    // 返回 intTuple 对象,可能为 NULL 或者包含了创建的 int 对象
    return intTuple;
}

.\numpy\numpy\_core\src\multiarray\conversion_utils.h

#ifndef NUMPY_CORE_SRC_MULTIARRAY_CONVERSION_UTILS_H_
#define NUMPY_CORE_SRC_MULTIARRAY_CONVERSION_UTILS_H_

#include "numpy/ndarraytypes.h"

// 定义整数转换函数,将 Python 对象转换为 PyArray_Dims 结构
NPY_NO_EXPORT int
PyArray_IntpConverter(PyObject *obj, PyArray_Dims *seq);

// 定义从 Python 整数对象转换为 npy_intp 类型的函数
NPY_NO_EXPORT int
PyArray_IntpFromPyIntConverter(PyObject *o, npy_intp *val);

// 定义可选整数转换函数,将 Python 对象转换为 PyArray_Dims 结构
NPY_NO_EXPORT int
PyArray_OptionalIntpConverter(PyObject *obj, PyArray_Dims *seq);

// 定义复制模式的枚举类型
typedef enum {
    NPY_COPY_NEVER = 0,
    NPY_COPY_ALWAYS = 1,
    NPY_COPY_IF_NEEDED = 2,
} NPY_COPYMODE;

// 定义转换函数,将 Python 对象转换为 NPY_COPYMODE 枚举类型
NPY_NO_EXPORT int
PyArray_CopyConverter(PyObject *obj, NPY_COPYMODE *copyflag);

// 定义类型转换和复制模式的枚举类型
typedef enum {
    NPY_AS_TYPE_COPY_IF_NEEDED = 0,
    NPY_AS_TYPE_COPY_ALWAYS = 1,
} NPY_ASTYPECOPYMODE;

// 定义类型转换和复制模式的转换函数
NPY_NO_EXPORT int
PyArray_AsTypeCopyConverter(PyObject *obj, NPY_ASTYPECOPYMODE *copyflag);

// 定义缓冲区转换函数,将 Python 对象转换为 PyArray_Chunk 结构
NPY_NO_EXPORT int
PyArray_BufferConverter(PyObject *obj, PyArray_Chunk *buf);

// 定义布尔值转换函数,将 Python 对象转换为 npy_bool 类型
NPY_NO_EXPORT int
PyArray_BoolConverter(PyObject *object, npy_bool *val);

// 定义可选布尔值转换函数,将 Python 对象转换为 int 类型
NPY_NO_EXPORT int
PyArray_OptionalBoolConverter(PyObject *object, int *val);

// 定义字节顺序转换函数,将 Python 对象转换为 char 类型
NPY_NO_EXPORT int
PyArray_ByteorderConverter(PyObject *obj, char *endian);

// 定义排序方式转换函数,将 Python 对象转换为 NPY_SORTKIND 枚举类型
NPY_NO_EXPORT int
PyArray_SortkindConverter(PyObject *obj, NPY_SORTKIND *sortkind);

// 定义搜索方向转换函数,将 Python 对象转换为 void 指针类型
NPY_NO_EXPORT int
PyArray_SearchsideConverter(PyObject *obj, void *addr);

// 定义将 Python 整数对象转换为 int 类型的函数
NPY_NO_EXPORT int
PyArray_PyIntAsInt(PyObject *o);

// 定义将 Python 整数对象转换为 npy_intp 类型的函数
NPY_NO_EXPORT npy_intp
PyArray_PyIntAsIntp(PyObject *o);

// 定义从索引序列转换为 npy_intp 数组的函数
NPY_NO_EXPORT npy_intp
PyArray_IntpFromIndexSequence(PyObject *seq, npy_intp *vals, npy_intp maxvals);

// 定义从序列转换为 npy_intp 数组的函数
NPY_NO_EXPORT int
PyArray_IntpFromSequence(PyObject *seq, npy_intp *vals, int maxvals);

// 定义类型字符串转换函数,接受 itemsize 和 gentype 两个整数参数
NPY_NO_EXPORT int
PyArray_TypestrConvert(int itemsize, int gentype);

// 定义将 npy_intp 类型值转换为 Python 整数对象的内联函数
static inline PyObject *
PyArray_PyIntFromIntp(npy_intp const value)
{
    // 根据平台字长选择不同的 PyLong_From* 函数转换
#if NPY_SIZEOF_INTP <= NPY_SIZEOF_LONG
    return PyLong_FromLong((long)value);
#else
    return PyLong_FromLongLong((npy_longlong)value);
#endif
}

// 定义将 npy_intp 数组转换为 Python 元组对象的函数
NPY_NO_EXPORT PyObject *
PyArray_IntTupleFromIntp(int len, npy_intp const *vals);

// 定义相关模式转换函数,将 Python 对象转换为 NPY_CORRELATEMODE 枚举类型
NPY_NO_EXPORT int
PyArray_CorrelatemodeConverter(PyObject *object, NPY_CORRELATEMODE *val);

// 定义选择类型转换函数,将 Python 对象转换为 NPY_SELECTKIND 枚举类型
NPY_NO_EXPORT int
PyArray_SelectkindConverter(PyObject *obj, NPY_SELECTKIND *selectkind);

/*
 * 将轴参数转换为长度为 ndim 的布尔标志数组,
 * 每个指定的轴对应的标志为 True。
 *
 * 如果 obj 是 None,则所有标志设置为 True。
 * 如果 obj 是元组,则元组中的每个轴设置为 True。
 * 如果 obj 是整数,则只有该轴设置为 True。
 */
NPY_NO_EXPORT int
PyArray_ConvertMultiAxis(PyObject *axis_in, int ndim, npy_bool *out_axis_flags);

// 设备字符串转换函数,将 Python 对象转换为 NPY_DEVICE 枚举类型
NPY_NO_EXPORT int
PyArray_DeviceConverterOptional(PyObject *object, NPY_DEVICE *device);

#endif  // NUMPY_CORE_SRC_MULTIARRAY_CONVERSION_UTILS_H_
/**
 * WARNING: This flag is a bad idea, but was the only way to both
 *   1) Support unpickling legacy pickles with object types.
 *   2) Deprecate (and later disable) usage of O4 and O8
 *
 * The key problem is that the pickled representation unpickles by
 * directly calling the dtype constructor, which has no way of knowing
 * that it is in an unpickle context instead of a normal context without
 * evil global state like we create here.
 */
extern NPY_NO_EXPORT NPY_TLS int evil_global_disable_warn_O4O8_flag;

/*
 * Convert function which replaces np._NoValue with NULL.
 * As a converter returns 0 on error and 1 on success.
 */
NPY_NO_EXPORT int
_not_NoValue(PyObject *obj, PyObject **out);

#endif  /* NUMPY_CORE_SRC_MULTIARRAY_CONVERSION_UTILS_H_ */


注释:

.\numpy\numpy\_core\src\multiarray\convert.c

/*
 * 设置 NPY_NO_DEPRECATED_API 到 NPY_API_VERSION,避免使用过时的 NumPy API
 * 定义 _MULTIARRAYMODULE,用于多维数组模块
 */
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
#define _MULTIARRAYMODULE

/*
 * 清除 PY_SSIZE_T_CLEAN 宏定义,确保使用最新的 Python 对象大小 API
 * 包含 Python.h 头文件,提供 Python C API 功能
 * 包含 structmember.h 头文件,用于定义 C 结构体的成员
 */
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <structmember.h>

/*
 * 包含 numpy 库配置相关头文件
 * 包含 numpy 数组对象头文件
 * 包含 numpy 数组标量头文件
 */
#include "npy_config.h"
#include "numpy/arrayobject.h"
#include "numpy/arrayscalars.h"

/*
 * 包含通用功能头文件
 * 包含数组对象功能头文件
 * 包含构造函数功能头文件
 * 包含数据类型元数据头文件
 * 包含映射头文件
 * 包含低级分步循环头文件
 * 包含标量类型头文件
 * 包含数组赋值头文件
 */
#include "common.h"
#include "arrayobject.h"
#include "ctors.h"
#include "dtypemeta.h"
#include "mapping.h"
#include "lowlevel_strided_loops.h"
#include "scalartypes.h"
#include "array_assign.h"

/*
 * 包含类型转换功能头文件
 * 包含数组强制转换功能头文件
 * 包含引用计数头文件
 */
#include "convert.h"
#include "array_coercion.h"
#include "refcount.h"

/*
 * 如果定义了 HAVE_FALLOCATE 并且在 Linux 平台上
 * 包含 fcntl.h 头文件,提供文件控制相关功能
 */
#if defined(HAVE_FALLOCATE) && defined(__linux__)
#include <fcntl.h>
#endif

/*
 * npy_fallocate 函数:为文件 fp 分配 nbytes 大小的磁盘空间
 * 允许文件系统进行更智能的分配决策,并在空间不足时快速退出
 * 返回 -1 并引发异常表示空间不足,忽略其他所有错误
 */
static int
npy_fallocate(npy_intp nbytes, FILE * fp)
{
    /*
     * 如果定义了 HAVE_FALLOCATE 并且在 Linux 平台上
     */
#if defined(HAVE_FALLOCATE) && defined(__linux__)
    int r;
    /* 对于小文件不值得进行系统调用 */
    if (nbytes < 16 * 1024 * 1024) {
        return 0;
    }

    /*
     * 刷新文件流,以防在 fallocate 调用和描述符中的未写数据之间存在意外交互
     */
    NPY_BEGIN_ALLOW_THREADS;
    r = fallocate(fileno(fp), 1, npy_ftell(fp), nbytes);
    NPY_END_ALLOW_THREADS;

    /*
     * 如果空间不足,则提前退出,并在写入过程中发现其他错误
     */
    if (r == -1 && errno == ENOSPC) {
        PyErr_Format(PyExc_OSError, "Not enough free space to write "
                     "%"NPY_INTP_FMT" bytes", nbytes);
        return -1;
    }
#endif
    return 0;
}

/*
 * recursive_tolist 函数:将 self 数组的子数组转换为列表
 * 从数据指针 dataptr 和维度 startdim 开始,直到 self 的最后一个维度
 * 返回新的引用对象
 */
static PyObject *
recursive_tolist(PyArrayObject *self, char *dataptr, int startdim)
{
    npy_intp i, n, stride;
    PyObject *ret, *item;

    /* 基本情况 */
    if (startdim >= PyArray_NDIM(self)) {
        return PyArray_GETITEM(self, dataptr);
    }

    n = PyArray_DIM(self, startdim);
    stride = PyArray_STRIDE(self, startdim);

    ret = PyList_New(n);
    if (ret == NULL) {
        return NULL;
    }

    for (i = 0; i < n; ++i) {
        item = recursive_tolist(self, dataptr, startdim+1);
        if (item == NULL) {
            Py_DECREF(ret);
            return NULL;
        }
        PyList_SET_ITEM(ret, i, item);

        dataptr += stride;
    }

    return ret;
}

/*
 * PyArray_ToList 函数:将数组 self 转换为 Python 列表
 * 调用 recursive_tolist 函数完成转换
 * 返回新的 Python 对象引用
 */
NPY_NO_EXPORT PyObject *
PyArray_ToList(PyArrayObject *self)
{
    return recursive_tolist(self, PyArray_DATA(self), 0);
}
/* XXX: FIXME --- add ordering argument to
   Allow Fortran ordering on write
   This will need the addition of a Fortran-order iterator.
 */
/* 在写入时添加排序参数
   允许使用Fortran排序
   这将需要添加Fortran排序迭代器。
 */

/*NUMPY_API
  To File
*/
/* NUMPY_API
   写入文件
*/

NPY_NO_EXPORT int
/* 不导出API */
PyArray_ToFile(PyArrayObject *self, FILE *fp, char *sep, char *format)
{
    npy_intp size;
    npy_intp n, n2;
    size_t n3, n4;
    PyArrayIterObject *it;
    PyObject *obj, *strobj, *tupobj, *byteobj;

    n3 = (sep ? strlen((const char *)sep) : 0);
    /* 计算分隔符的长度,如果不存在则为0 */

    if (n3 == 0) {
        /* binary data */
        /* 二进制数据 */

        if (PyDataType_FLAGCHK(PyArray_DESCR(self), NPY_LIST_PICKLE)) {
            PyErr_SetString(PyExc_OSError,
                    "cannot write object arrays to a file in binary mode");
            return -1;
        }
        /* 如果数组描述符标志包含NPY_LIST_PICKLE,抛出异常不能以二进制模式写入对象数组 */

        if (PyArray_ITEMSIZE(self) == 0) {
            /* For zero-width data types there's nothing to write */
            /* 对于零宽度的数据类型,没有内容需要写入 */
            return 0;
        }

        if (npy_fallocate(PyArray_NBYTES(self), fp) != 0) {
            /* 使用npy_fallocate分配内存失败时返回-1 */
            return -1;
        }

        if (PyArray_ISCONTIGUOUS(self)) {
            /* 如果数组是连续存储的 */

            size = PyArray_SIZE(self);
            /* 获取数组的大小 */
            NPY_BEGIN_ALLOW_THREADS;
            /* 开始允许多线程 */
#if defined(_WIN64)
            /*
             * 解决 Win64 fwrite() Bug。问题详见 gh-2256
             * 本地 64 位 Windows 运行时存在此问题,上述代码也将触发 UCRT(未触发的情况也可能更精确)。
             *
             * 如果您修改了此代码,请运行以下测试,该测试因速度慢而已从测试套件中移除。
             * 原始失败模式涉及在 tofile() 过程中的无限循环。
             *
             * import tempfile, numpy as np
             * from numpy.testing import (assert_)
             * fourgbplus = 2**32 + 2**16
             * testbytes = np.arange(8, dtype=np.int8)
             * n = len(testbytes)
             * flike = tempfile.NamedTemporaryFile()
             * f = flike.file
             * np.tile(testbytes, fourgbplus // testbytes.nbytes).tofile(f)
             * flike.seek(0)
             * a = np.fromfile(f, dtype=np.int8)
             * flike.close()
             * assert_(len(a) == fourgbplus)
             * # check only start and end for speed:
             * assert_((a[:n] == testbytes).all())
             * assert_((a[-n:] == testbytes).all())
             */
            {
                // 计算每次写入的最大字节数,避免 Win64 下 fwrite() 的问题
                size_t maxsize = 2147483648 / (size_t)PyArray_ITEMSIZE(self);
                size_t chunksize;

                n = 0;
                // 循环写入直到所有数据被处理完毕
                while (size > 0) {
                    // 确定当前循环可以写入的数据块大小
                    chunksize = (size > maxsize) ? maxsize : size;
                    // 调用 fwrite() 写入数据
                    n2 = fwrite((const void *)
                                 ((char *)PyArray_DATA(self) + (n * PyArray_ITEMSIZE(self))),
                                 (size_t) PyArray_ITEMSIZE(self),
                                 chunksize, fp);
                    // 检查写入是否完整,若不完整则跳出循环
                    if (n2 < chunksize) {
                        break;
                    }
                    // 更新已写入数据的总量和剩余数据的大小
                    n += n2;
                    size -= chunksize;
                }
                // 重置 size 为数组的总大小
                size = PyArray_SIZE(self);
            }
#else
            // 非 Win64 平台下直接调用 fwrite() 写入数据
            n = fwrite((const void *)PyArray_DATA(self),
                    (size_t) PyArray_ITEMSIZE(self),
                    (size_t) size, fp);
#endif
#else
            // 结束任何可能存在的线程访问
            NPY_END_ALLOW_THREADS;
            // 如果写入的字节数小于请求的字节数,抛出异常并返回-1
            if (n < size) {
                PyErr_Format(PyExc_OSError,
                        "%ld requested and %ld written",
                        (long) size, (long) n);
                return -1;
            }
        }
        else {
            // 定义线程开始的宏
            NPY_BEGIN_THREADS_DEF;

            // 创建数组迭代器对象
            it = (PyArrayIterObject *) PyArray_IterNew((PyObject *)self);
            // 开始线程
            NPY_BEGIN_THREADS;
            // 当迭代器的索引小于其大小时循环
            while (it->index < it->size) {
                // 将当前迭代器位置的数据写入文件
                if (fwrite((const void *)it->dataptr,
                            (size_t) PyArray_ITEMSIZE(self),
                            1, fp) < 1) {
                    // 结束线程
                    NPY_END_THREADS;
                    // 格式化异常信息,并返回-1
                    PyErr_Format(PyExc_OSError,
                            "problem writing element %" NPY_INTP_FMT
                            " to file", it->index);
                    Py_DECREF(it);
                    return -1;
                }
                // 移动迭代器到下一个元素
                PyArray_ITER_NEXT(it);
            }
            // 结束线程
            NPY_END_THREADS;
            // 释放迭代器对象的引用
            Py_DECREF(it);
        }
    }
    else:
        """
        * text data
        """

        # 创建一个 PyArrayIterObject 迭代器对象,用于迭代数组 self
        it = (PyArrayIterObject *) PyArray_IterNew((PyObject *)self)
        # 如果定义了格式字符串 format,则计算其长度;否则长度为 0
        n4 = (format ? strlen((const char *)format) : 0)
        # 当迭代器的索引小于数组的大小时,执行循环
        while (it->index < it->size):
            """
            * This is as documented.  If we have a low precision float value
            * then it may convert to float64 and store unnecessary digits.
            * TODO: This could be fixed, by not using `arr.item()` or using
            *       the array printing/formatting functionality.
            """
            # 获取数组中当前迭代位置的元素对象 obj
            obj = PyArray_GETITEM(self, it->dataptr)
            # 如果获取失败,则释放迭代器并返回 -1
            if (obj == NULL):
                Py_DECREF(it)
                return -1
            # 如果没有指定格式字符串
            if (n4 == 0):
                """
                * standard writing
                """
                # 将 obj 转换为字符串对象 strobj
                strobj = PyObject_Str(obj)
                # 释放 obj 对象的引用计数
                Py_DECREF(obj)
                # 如果转换失败,则释放迭代器并返回 -1
                if (strobj == NULL):
                    Py_DECREF(it)
                    return -1
            else:
                """
                * use format string
                """
                # 创建一个包含 obj 的单元素元组对象 tupobj
                tupobj = PyTuple_New(1)
                # 如果创建失败,则释放迭代器并返回 -1
                if (tupobj == NULL):
                    Py_DECREF(it)
                    return -1
                # 将 obj 设置为元组的第一个元素
                PyTuple_SET_ITEM(tupobj, 0, obj)
                # 根据格式字符串 format 创建 Unicode 字符串对象 obj
                obj = PyUnicode_FromString((const char *)format)
                # 如果创建失败,则释放 tupobj 和迭代器并返回 -1
                if (obj == NULL):
                    Py_DECREF(tupobj)
                    Py_DECREF(it)
                    return -1
                # 格式化 Unicode 字符串 obj 和 tupobj,返回格式化后的字符串 strobj
                strobj = PyUnicode_Format(obj, tupobj)
                # 释放 obj 和 tupobj 对象的引用计数
                Py_DECREF(obj)
                Py_DECREF(tupobj)
                # 如果格式化失败,则释放迭代器并返回 -1
                if (strobj == NULL):
                    Py_DECREF(it)
                    return -1
            # 将 Unicode 字符串 strobj 转换为 ASCII 字符串 byteobj
            byteobj = PyUnicode_AsASCIIString(strobj)
            # 在多线程环境下允许线程,获取 byteobj 的大小 n2
            NPY_BEGIN_ALLOW_THREADS
            n2 = PyBytes_GET_SIZE(byteobj)
            # 将 byteobj 的内容写入文件 fp
            n = fwrite(PyBytes_AS_STRING(byteobj), 1, n2, fp)
            NPY_END_ALLOW_THREADS
            # 释放 byteobj 对象的引用计数
            Py_DECREF(byteobj)
            # 如果写入的字节数小于应写入的字节数 n2,则抛出异常并释放 strobj 和迭代器,返回 -1
            if (n < n2):
                PyErr_Format(PyExc_OSError,
                             "problem writing element %" NPY_INTP_FMT " to file", it->index)
                Py_DECREF(strobj)
                Py_DECREF(it)
                return -1
            # 如果不是最后一个元素,则在文件中写入分隔符 sep
            if (it->index != it->size - 1):
                if (fwrite(sep, 1, n3, fp) < n3):
                    PyErr_Format(PyExc_OSError,
                                 "problem writing separator to file")
                    Py_DECREF(strobj)
                    Py_DECREF(it)
                    return -1
            # 释放 strobj 对象的引用计数
            Py_DECREF(strobj)
            # 移动到迭代器的下一个位置
            PyArray_ITER_NEXT(it)
        # 释放迭代器对象 it 的引用计数
        Py_DECREF(it)
    # 返回 0 表示成功
    return 0
/*NUMPY_API*/
NPY_NO_EXPORT PyObject *
PyArray_ToString(PyArrayObject *self, NPY_ORDER order)
{
    npy_intp numbytes;              // 存储数组总字节数
    npy_intp i;                     // 循环计数器
    char *dptr;                     // 指向目标字符串的指针
    int elsize;                     // 数组元素大小
    PyObject *ret;                  // 返回的Python对象
    PyArrayIterObject *it;          // 数组迭代器对象

    if (order == NPY_ANYORDER)
        order = PyArray_ISFORTRAN(self) ? NPY_FORTRANORDER : NPY_CORDER;

    /*        if (PyArray_TYPE(self) == NPY_OBJECT) {
              PyErr_SetString(PyExc_ValueError, "a string for the data" \
              "in an object array is not appropriate");
              return NULL;
              }
    */
    // 如果数组类型为对象数组,抛出错误并返回空指针
    numbytes = PyArray_NBYTES(self); // 计算数组的总字节数
    // 如果数组是C连续的且按顺序为C,或者是Fortran连续的且按顺序为Fortran,直接从数组数据创建字符串对象
    if ((PyArray_IS_C_CONTIGUOUS(self) && (order == NPY_CORDER))
        || (PyArray_IS_F_CONTIGUOUS(self) && (order == NPY_FORTRANORDER))) {
        ret = PyBytes_FromStringAndSize(PyArray_DATA(self), (Py_ssize_t) numbytes);
    }
    else {
        PyObject *new;
        if (order == NPY_FORTRANORDER) {
            /* iterators are always in C-order */
            // 如果按Fortran顺序,需要先转置数组为C顺序
            new = PyArray_Transpose(self, NULL);
            if (new == NULL) {
                return NULL;
            }
        }
        else {
            Py_INCREF(self);
            new = (PyObject *)self;
        }
        // 创建数组迭代器
        it = (PyArrayIterObject *)PyArray_IterNew(new);
        Py_DECREF(new);
        if (it == NULL) {
            return NULL;
        }
        // 根据数组总字节数创建新的字符串对象
        ret = PyBytes_FromStringAndSize(NULL, (Py_ssize_t) numbytes);
        if (ret == NULL) {
            Py_DECREF(it);
            return NULL;
        }
        // 将数组数据复制到字符串中
        dptr = PyBytes_AS_STRING(ret);
        i = it->size;
        elsize = PyArray_ITEMSIZE(self);
        while (i--) {
            memcpy(dptr, it->dataptr, elsize);
            dptr += elsize;
            PyArray_ITER_NEXT(it);
        }
        Py_DECREF(it);
    }
    return ret;  // 返回字符串对象
}

/*NUMPY_API*/
NPY_NO_EXPORT int
PyArray_FillWithScalar(PyArrayObject *arr, PyObject *obj)
{

    if (PyArray_FailUnlessWriteable(arr, "assignment destination") < 0) {
        return -1;
    }

    /*
     * If we knew that the output array has at least one element, we would
     * not actually need a helping buffer, we always null it, just in case.
     *
     * (The longlong here should help with alignment.)
     */
    // 用于存储标量值的缓冲区
    npy_longlong value_buffer_stack[4] = {0};
    char *value_buffer_heap = NULL;
    char *value = (char *)value_buffer_stack;
    PyArray_Descr *descr = PyArray_DESCR(arr);

    // 如果数组元素大小超过堆栈缓冲区大小,需要分配堆内存
    if ((size_t)descr->elsize > sizeof(value_buffer_stack)) {
        /* We need a large temporary buffer... */
        // 分配足够大的临时缓冲区
        value_buffer_heap = PyObject_Calloc(1, descr->elsize);
        if (value_buffer_heap == NULL) {
            PyErr_NoMemory();
            return -1;
        }
        value = value_buffer_heap;
    }
    // 将Python对象obj打包成数组元素
    if (PyArray_Pack(descr, value, obj) < 0) {
        PyMem_FREE(value_buffer_heap);
        return -1;
    }

    /*
     * There is no cast anymore, the above already coerced using scalar
     * coercion rules
     */
    // 不再需要强制转换,上述操作已经使用标量强制转换规则执行了
    // 返回成功状态

    return 0;
}
    # 调用 raw_array_assign_scalar 函数执行数组的标量赋值操作,并将返回值赋给 retcode
    int retcode = raw_array_assign_scalar(
            PyArray_NDIM(arr), PyArray_DIMS(arr), descr,
            PyArray_BYTES(arr), PyArray_STRIDES(arr),
            descr, value);

    # 检查数据类型 descr 是否需要引用计数检查,如果需要,则调用 PyArray_ClearBuffer 清除缓冲区
    if (PyDataType_REFCHK(descr)) {
        PyArray_ClearBuffer(descr, value, 0, 1, 1);
    }
    # 释放 value_buffer_heap 指向的内存块
    PyMem_FREE(value_buffer_heap);

    # 返回 retcode 作为函数的返回值
    return retcode;
/*
 * Internal function to fill an array with zeros.
 * Used in einsum and dot, which ensures the dtype is, in some sense, numerical
 * and not a str or struct
 *
 * dst: The destination array.
 * wheremask: If non-NULL, a boolean mask specifying where to set the values.
 *
 * Returns 0 on success, -1 on failure.
 */
NPY_NO_EXPORT int
PyArray_AssignZero(PyArrayObject *dst,
                   PyArrayObject *wheremask)
{
    // 初始化返回码
    int retcode = 0;
    
    // 如果目标数组是对象数组
    if (PyArray_ISOBJECT(dst)) {
        // 创建一个表示整数0的 Python 对象
        PyObject * pZero = PyLong_FromLong(0);
        // 使用 PyArray_AssignRawScalar 函数将整数0赋值给目标数组
        retcode = PyArray_AssignRawScalar(dst, PyArray_DESCR(dst),
                                     (char *)&pZero, wheremask, NPY_SAFE_CASTING);
        // 释放 Python 对象 pZero 的引用计数
        Py_DECREF(pZero);
    }
    else {
        /* 创建一个原始的布尔标量,其值为 False */
        // 从 NPY_BOOL 类型创建一个描述符
        PyArray_Descr *bool_dtype = PyArray_DescrFromType(NPY_BOOL);
        if (bool_dtype == NULL) {
            return -1;  // 如果创建描述符失败则返回 -1
        }
        npy_bool value = 0;  // 初始化布尔值为 False

        // 使用 PyArray_AssignRawScalar 函数将布尔值赋值给目标数组
        retcode = PyArray_AssignRawScalar(dst, bool_dtype, (char *)&value,
                                          wheremask, NPY_SAFE_CASTING);

        // 释放布尔类型的描述符
        Py_DECREF(bool_dtype);
    }
    // 返回操作结果码
    return retcode;
}



/*NUMPY_API
 * Copy an array.
 */
NPY_NO_EXPORT PyObject *
PyArray_NewCopy(PyArrayObject *obj, NPY_ORDER order)
{
    // 定义返回的数组对象指针
    PyArrayObject *ret;

    // 如果传入的数组对象为空,则抛出数值错误异常并返回空指针
    if (obj == NULL) {
        PyErr_SetString(PyExc_ValueError,
            "obj is NULL in PyArray_NewCopy");
        return NULL;
    }

    // 使用 PyArray_NewLikeArray 函数根据原数组对象创建一个相似的新数组对象
    ret = (PyArrayObject *)PyArray_NewLikeArray(obj, order, NULL, 1);
    if (ret == NULL) {
        return NULL;  // 如果创建新数组失败则返回空指针
    }

    // 使用 PyArray_AssignArray 函数将原数组的数据复制到新数组中
    if (PyArray_AssignArray(ret, obj, NULL, NPY_UNSAFE_CASTING) < 0) {
        Py_DECREF(ret);
        return NULL;  // 如果复制数据失败则释放新数组并返回空指针
    }

    // 返回新创建的数组对象
    return (PyObject *)ret;
}



/*NUMPY_API
 * View
 * steals a reference to type -- accepts NULL
 */
NPY_NO_EXPORT PyObject *
PyArray_View(PyArrayObject *self, PyArray_Descr *type, PyTypeObject *pytype)
{
    // 定义返回的数组对象指针
    PyArrayObject *ret = NULL;
    PyArray_Descr *dtype;
    PyTypeObject *subtype;
    int flags;

    // 如果传入的类型非空,则使用该类型,否则使用 self 的类型
    if (pytype) {
        subtype = pytype;
    }
    else {
        subtype = Py_TYPE(self);
    }

    // 获取 self 的数据描述符和标志位
    dtype = PyArray_DESCR(self);
    flags = PyArray_FLAGS(self);

    // 增加数据描述符的引用计数,并使用 PyArray_NewFromDescr_int 函数创建新的数组对象
    Py_INCREF(dtype);
    ret = (PyArrayObject *)PyArray_NewFromDescr_int(
            subtype, dtype,
            PyArray_NDIM(self), PyArray_DIMS(self), PyArray_STRIDES(self),
            PyArray_DATA(self),
            flags, (PyObject *)self, (PyObject *)self,
            _NPY_ARRAY_ENSURE_DTYPE_IDENTITY);
    if (ret == NULL) {
        Py_XDECREF(type);
        return NULL;  // 如果创建新数组对象失败则释放 type 并返回空指针
    }

    // 如果传入的类型非空,则将该类型设置为新数组对象的 dtype 属性
    if (type != NULL) {
        if (PyObject_SetAttrString((PyObject *)ret, "dtype",
                                   (PyObject *)type) < 0) {
            Py_DECREF(ret);
            Py_DECREF(type);
            return NULL;  // 如果设置 dtype 属性失败则释放 ret 和 type 并返回空指针
        }
        Py_DECREF(type);
    }
    // 返回新创建的数组对象
    return (PyObject *)ret;
}