NumPy-源码解析-七十一-

103 阅读1小时+

NumPy 源码解析(七十一)

.\numpy\numpy\_core\src\multiarray\refcount.h

#ifndef NUMPY_CORE_SRC_MULTIARRAY_REFCOUNT_H_
#define NUMPY_CORE_SRC_MULTIARRAY_REFCOUNT_H_

// 声明一个不导出的函数,用于清除数组描述符指向数据的缓冲区
NPY_NO_EXPORT int
PyArray_ClearBuffer(
        PyArray_Descr *descr, char *data,
        npy_intp stride, npy_intp size, int aligned);

// 声明一个不导出的函数,用于清除整个数组对象
NPY_NO_EXPORT int
PyArray_ClearArray(PyArrayObject *arr);

// 声明一个不导出的函数,用于增加数组项的引用计数
NPY_NO_EXPORT void
PyArray_Item_INCREF(char *data, PyArray_Descr *descr);

// 声明一个不导出的函数,用于减少数组项的引用计数
NPY_NO_EXPORT void
PyArray_Item_XDECREF(char *data, PyArray_Descr *descr);

// 声明一个不导出的函数,用于增加数组对象的引用计数
NPY_NO_EXPORT int
PyArray_INCREF(PyArrayObject *mp);

// 声明一个不导出的函数,用于减少数组对象的引用计数
NPY_NO_EXPORT int
PyArray_XDECREF(PyArrayObject *mp);

// 声明一个不导出的函数,用于将数组对象的元素设置为None对象
NPY_NO_EXPORT int
PyArray_SetObjectsToNone(PyArrayObject *arr);

#endif  /* NUMPY_CORE_SRC_MULTIARRAY_REFCOUNT_H_ */

.\numpy\numpy\_core\src\multiarray\scalarapi.c

/*
   定义 NPY_NO_DEPRECATED_API 为 NPY_API_VERSION,避免使用已废弃的 NumPy API 版本
   定义 _MULTIARRAYMODULE,用于多维数组模块

   引入必要的头文件和库
*/
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
#define _MULTIARRAYMODULE

#include <Python.h>             // Python C API 的主头文件
#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 "array_coercion.h"     // 数组类型转换相关
#include "ctors.h"              // 构造函数相关
#include "descriptor.h"         // 数组描述符相关
#include "dtypemeta.h"          // 数据类型元信息相关
#include "scalartypes.h"        // 标量类型相关

#include "common.h"             // 公共函数和宏定义

// 定义静态函数 _descr_from_subtype,根据子类型创建 PyArray_Descr 对象
static PyArray_Descr *
_descr_from_subtype(PyObject *type)
{
    PyObject *mro;
    mro = ((PyTypeObject *)type)->tp_mro;
    // 如果类型的方法解析顺序(MRO)长度小于 2,返回通用的对象类型描述符
    if (PyTuple_GET_SIZE(mro) < 2) {
        return PyArray_DescrFromType(NPY_OBJECT);
    }
    // 否则返回基于 MRO 的第二个项的类型描述符
    return PyArray_DescrFromTypeObject(PyTuple_GET_ITEM(mro, 1));
}

// 定义 NPY_NO_EXPORT 的标量值提取函数,根据给定的描述符提取标量值
NPY_NO_EXPORT void *
scalar_value(PyObject *scalar, PyArray_Descr *descr)
{
    int type_num;
    int align;
    uintptr_t memloc;
    // 如果描述符为 NULL,根据标量对象生成描述符,并获取其类型编号
    if (descr == NULL) {
        descr = PyArray_DescrFromScalar(scalar);
        type_num = descr->type_num;
        Py_DECREF(descr);
    }
    else {
        // 否则直接获取描述符的类型编号
        type_num = descr->type_num;
    }
    // 根据类型编号进行不同的处理分支
    switch (type_num) {
#define CASE(ut,lt) case NPY_##ut: return &PyArrayScalar_VAL(scalar, lt)
        // 不同类型的标量值提取宏定义分支
        CASE(BOOL, Bool);
        CASE(BYTE, Byte);
        CASE(UBYTE, UByte);
        CASE(SHORT, Short);
        CASE(USHORT, UShort);
        CASE(INT, Int);
        CASE(UINT, UInt);
        CASE(LONG, Long);
        CASE(ULONG, ULong);
        CASE(LONGLONG, LongLong);
        CASE(ULONGLONG, ULongLong);
        CASE(HALF, Half);
        CASE(FLOAT, Float);
        CASE(DOUBLE, Double);
        CASE(LONGDOUBLE, LongDouble);
        CASE(CFLOAT, CFloat);
        CASE(CDOUBLE, CDouble);
        CASE(CLONGDOUBLE, CLongDouble);
        CASE(OBJECT, Object);
        CASE(DATETIME, Datetime);
        CASE(TIMEDELTA, Timedelta);
#undef CASE
        // 对于字符串类型,返回字符串对象的指针作为标量值
        case NPY_STRING:
            return (void *)PyBytes_AsString(scalar);
        // 对于 Unicode 类型,如果未初始化则进行延迟初始化,并返回 Unicode 数据指针
        case NPY_UNICODE:
            /* 懒初始化,以减少字符串标量占用的内存 */
            if (PyArrayScalar_VAL(scalar, Unicode) == NULL) {
                Py_UCS4 *raw_data = PyUnicode_AsUCS4Copy(scalar);
                if (raw_data == NULL) {
                    return NULL;
                }
                PyArrayScalar_VAL(scalar, Unicode) = raw_data;
                return (void *)raw_data;
            }
            return PyArrayScalar_VAL(scalar, Unicode);
        // 对于 VOID 类型,直接返回 VOID 数据的指针作为标量值
        case NPY_VOID:
            /* 注意:这里不需要使用 &,因此不能使用 CASE 宏 */
            return PyArrayScalar_VAL(scalar, Void);
    }

    /*
     * 如果标量是用户定义类型,并且关联有(注册的)dtype,
     * 那么它不能是灵活的(用户 dtype 不能是灵活的),
     * 因此我们可以(而且基本上只能)假设以下逻辑始终有效。
     * 即假设这个逻辑对我们的大多数类型也有效。
     */

    /*
     * 使用对齐标志确定在 PyObject_HEAD 之后数据从何处开始
     */
    memloc = (uintptr_t)scalar;
    memloc += sizeof(PyObject);
    /* 现在将内存地址向最接近的对齐值进行调整 */
    align = descr->alignment;  // 获取描述符中的对齐值
    if (align > 1) {  // 如果对齐值大于1
        memloc = ((memloc + align - 1) / align) * align;  // 根据对齐值调整内存地址
    }
    return (void *)memloc;  // 将调整后的内存地址转换为void指针并返回
/*NUMPY_API
 * return 1 if an object is exactly a numpy scalar
 */
NPY_NO_EXPORT int
PyArray_CheckAnyScalarExact(PyObject * obj)
{
    // 如果传入的对象为空,则设置错误并返回0
    if (obj == NULL) {
        PyErr_SetString(PyExc_ValueError,
            "obj is NULL in PyArray_CheckAnyScalarExact");
        return 0;
    }

    // 调用is_anyscalar_exact函数检查对象是否为精确的任意标量
    return is_anyscalar_exact(obj);
}

/*NUMPY_API
 * Convert to c-type
 *
 * no error checking is performed -- ctypeptr must be same type as scalar
 * in case of flexible type, the data is not copied
 * into ctypeptr which is expected to be a pointer to pointer
 */
NPY_NO_EXPORT void
PyArray_ScalarAsCtype(PyObject *scalar, void *ctypeptr)
{
    PyArray_Descr *typecode;
    void *newptr;

    // 从标量对象中获取描述符
    typecode = PyArray_DescrFromScalar(scalar);
    // 通过标量值函数获取标量的内存地址
    newptr = scalar_value(scalar, typecode);

    // 如果类型码为扩展类型,ctypeptr是指针的指针,直接赋值
    if (PyTypeNum_ISEXTENDED(typecode->type_num)) {
        void **ct = (void **)ctypeptr;
        *ct = newptr;
    }
    // 否则,使用memcpy将数据拷贝到ctypeptr指向的内存中
    else {
        memcpy(ctypeptr, newptr, typecode->elsize);
    }
    Py_DECREF(typecode);
    return;
}

/*NUMPY_API
 * Cast Scalar to c-type
 *
 * The output buffer must be large-enough to receive the value, this function
 * should only be used for subclasses of `np.generic`, we can only guarantee
 * it works for NumPy builtins.
 */
NPY_NO_EXPORT int
PyArray_CastScalarToCtype(PyObject *scalar, void *ctypeptr,
                          PyArray_Descr *outcode)
{
    PyArray_Descr* descr;

    // 获取标量对象的描述符
    descr = PyArray_DescrFromScalar(scalar);
    if (descr == NULL) {
        return -1;
    }
    // 获取标量值的内存地址
    void *src = scalar_value(scalar, descr);
    if (src == NULL) {
        Py_DECREF(descr);
        return -1;
    }

    // 调用np_cast_raw_scalar_item进行类型转换
    int res = npy_cast_raw_scalar_item(descr, src, outcode, ctypeptr);
    Py_DECREF(descr);
    return res;
}

/*NUMPY_API
 * Cast Scalar to c-type
 */
NPY_NO_EXPORT int
PyArray_CastScalarDirect(PyObject *scalar, PyArray_Descr *indescr,
                         void *ctypeptr, int outtype)
{
    // 获取输出数据类型的描述符
    PyArray_Descr *out_dt = PyArray_DescrFromType(outtype);
    if (out_dt == NULL) {
        return -1;
    }
    // 获取输入标量值的内存地址
    void *src = scalar_value(scalar, indescr);
    if (src == NULL) {
        Py_DECREF(out_dt);
        return -1;
    }

    // 调用np_cast_raw_scalar_item进行直接类型转换
    int res = npy_cast_raw_scalar_item(indescr, src, out_dt, ctypeptr);
    Py_DECREF(out_dt);
    return res;
}

/*NUMPY_API
 * Get 0-dim array from scalar
 *
 * 0-dim array from array-scalar object
 * always contains a copy of the data
 * unless outcode is NULL, it is of void type and the referrer does
 * not own it either.
 *
 * steals reference to outcode
 */
NPY_NO_EXPORT PyObject *
PyArray_FromScalar(PyObject *scalar, PyArray_Descr *outcode)
{
    /* convert to 0-dim array of scalar typecode */
    // 获取标量对象的类型描述符
    PyArray_Descr *typecode = PyArray_DescrFromScalar(scalar);
    if (typecode == NULL) {
        Py_XDECREF(outcode);
        return NULL;
    }

    // ...
}
    # 检查是否为 void 类型,并且标量对象没有所有权且输出代码为空
    if ((typecode->type_num == NPY_VOID) &&
            !(((PyVoidScalarObject *)scalar)->flags & NPY_ARRAY_OWNDATA) &&
            outcode == NULL) {
        # 创建新的数组对象,使用给定的描述符和基础数据
        return PyArray_NewFromDescrAndBase(
                &PyArray_Type, typecode,
                0, NULL, NULL,
                ((PyVoidScalarObject *)scalar)->obval,
                ((PyVoidScalarObject *)scalar)->flags,
                NULL, (PyObject *)scalar);
    }

    # 使用给定的描述符创建新的数组对象
    PyArrayObject *r = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type,
            typecode,
            0, NULL,
            NULL, NULL, 0, NULL);
    if (r == NULL) {
        # 如果创建失败,释放输出代码对象并返回空
        Py_XDECREF(outcode);
        return NULL;
    }
    /* the dtype used by the array may be different to the one requested */
    # 数组使用的数据类型可能与请求的不同

    # 检查数据类型标志是否支持使用 setitem 方法
    typecode = PyArray_DESCR(r);
    if (PyDataType_FLAGCHK(typecode, NPY_USE_SETITEM)) {
        # 如果支持,调用数组类型的 setitem 函数设置数据
        if (PyDataType_GetArrFuncs(typecode)->setitem(scalar, PyArray_DATA(r), r) < 0) {
            # 如果设置失败,释放数组对象和输出代码对象并返回空
            Py_DECREF(r);
            Py_XDECREF(outcode);
            return NULL;
        }
    }
    else {
        # 否则,获取标量对象的内存指针
        char *memptr = scalar_value(scalar, typecode);

        # 将标量对象的数据复制到数组对象中
        memcpy(PyArray_DATA(r), memptr, PyArray_ITEMSIZE(r));
        if (PyDataType_FLAGCHK(typecode, NPY_ITEM_HASOBJECT)) {
            /* Need to INCREF just the PyObject portion */
            # 如果数据类型标志表明对象需要增加引用计数,则增加对象部分的引用计数
            PyArray_Item_INCREF(memptr, typecode);
        }
    }

    # 如果输出代码为空,直接返回数组对象
    if (outcode == NULL) {
        return (PyObject *)r;
    }
    # 如果输出代码与数组数据类型等价
    if (PyArray_EquivTypes(outcode, typecode)) {
        # 如果数据类型等价且长度相同(对于扩展类型)
        if (!PyTypeNum_ISEXTENDED(typecode->type_num)
                || (outcode->elsize == typecode->elsize)) {
            '''
             * 由于类型是等价的,并且我们还没有将数组传递给任何人,
             * 让我们把数据类型固定为请求的类型,即使它与传入的类型是等价的。
             '''
            # 将数组的描述符设置为输出代码
            Py_SETREF(((PyArrayObject_fields *)r)->descr, outcode);

            return (PyObject *)r;
        }
    }

    # 如果需要,将数组转换为所需的输出数据类型
    PyObject *ret = PyArray_CastToType(r, outcode, 0);
    Py_DECREF(r);
    return ret;
/*New reference */
/*NUMPY_API
 */
/* 从 Python 类型对象创建 NumPy 数组描述符。
   如果类型是内置类型,则使用其类型编号。
   返回对应的数组描述符对象或者在出错时返回 NULL。
*/
NPY_NO_EXPORT PyArray_Descr *
PyArray_DescrFromTypeObject(PyObject *type)
{
    /* 如果是内置类型,获取其类型编号 */
    int typenum = _typenum_fromtypeobj(type, 1);
    if (typenum != NPY_NOTYPE) {
        // 根据类型编号获取对应的数组描述符对象并返回
        return PyArray_DescrFromType(typenum);
    }

    /* 检查通用的类型 */
    if ((type == (PyObject *) &PyNumberArrType_Type) ||
            (type == (PyObject *) &PyInexactArrType_Type) ||
            (type == (PyObject *) &PyFloatingArrType_Type)) {
        // 警告:将 `np.inexact` 或 `np.floating` 转换为 dtype 已不建议使用。
        // 返回默认的 `float64` 数组描述符对象,不严格正确。
        if (DEPRECATE("Converting `np.inexact` or `np.floating` to "
                      "a dtype is deprecated. The current result is `float64` "
                      "which is not strictly correct.") < 0) {
            return NULL;
        }
        typenum = NPY_DOUBLE;
    }
    else if (type == (PyObject *) &PyComplexFloatingArrType_Type) {
        // 警告:将 `np.complex` 转换为 dtype 已不建议使用。
        // 返回默认的 `complex128` 数组描述符对象,不严格正确。
        if (DEPRECATE("Converting `np.complex` to a dtype is deprecated. "
                      "The current result is `complex128` which is not "
                      "strictly correct.") < 0) {
            return NULL;
        }
        typenum = NPY_CDOUBLE;
    }
    else if ((type == (PyObject *) &PyIntegerArrType_Type) ||
            (type == (PyObject *) &PySignedIntegerArrType_Type)) {
        // 警告:将 `np.integer` 或 `np.signedinteger` 转换为 dtype 已不建议使用。
        // 返回默认的 `np.int_` 或者系统相关的整数类型数组描述符对象,不严格正确。
        if (DEPRECATE("Converting `np.integer` or `np.signedinteger` to "
                      "a dtype is deprecated. The current result is "
                      "`np.dtype(np.int_)` which is not strictly correct. "
                      "Note that the result depends on the system. To ensure "
                      "stable results use may want to use `np.int64` or "
                      "`np.int32`.") < 0) {
            return NULL;
        }
        typenum = NPY_LONG;
    }
    else if (type == (PyObject *) &PyUnsignedIntegerArrType_Type) {
        // 警告:将 `np.unsignedinteger` 转换为 dtype 已不建议使用。
        // 返回默认的 `np.uint` 或者系统相关的无符号整数类型数组描述符对象,不严格正确。
        if (DEPRECATE("Converting `np.unsignedinteger` to a dtype is "
                      "deprecated. The current result is `np.dtype(np.uint)` "
                      "which is not strictly correct. Note that the result "
                      "depends on the system. To ensure stable results you may "
                      "want to use `np.uint64` or `np.uint32`.") < 0) {
            return NULL;
        }
        typenum = NPY_ULONG;
    }
    else if (type == (PyObject *) &PyCharacterArrType_Type) {
        // 警告:将 `np.character` 转换为 dtype 已不建议使用。
        // 返回默认的 `np.str_` 或者 'S1' 类型数组描述符对象,不严格正确。
        if (DEPRECATE("Converting `np.character` to a dtype is deprecated. "
                      "The current result is `np.dtype(np.str_)` "
                      "which is not strictly correct. Note that `np.character` "
                      "is generally deprecated and 'S1' should be used.") < 0) {
            return NULL;
        }
        typenum = NPY_STRING;
    }
    /*
     * 否则 --- type 是数组标量的子类型,
     * 没有对应于注册的数据类型对象。
     */
    else if ((type == (PyObject *) &PyGenericArrType_Type) ||
            (type == (PyObject *) &PyFlexibleArrType_Type)) {
        /*
         * 如果是 `np.generic` 或 `np.flexible` 类型,
         * 转换为 dtype 已经被弃用。
         * 当前结果是 `np.dtype(np.void)`,
         * 这不是严格正确的。
         */
        if (DEPRECATE("Converting `np.generic` to a dtype is "
                      "deprecated. The current result is `np.dtype(np.void)` "
                      "which is not strictly correct.") < 0) {
            return NULL;
        }
        // 设置 typenum 为 NPY_VOID
        typenum = NPY_VOID;
    }

    // 如果 typenum 不等于 NPY_NOTYPE
    if (typenum != NPY_NOTYPE) {
        // 返回对应 typenum 的 PyArray_Descr 对象
        return PyArray_DescrFromType(typenum);
    }

    /*
     * 否则 --- type 是数组标量的子类型,
     * 没有对应于注册的数据类型对象。
     */

    /* 对于 VOID 子类型执行特殊操作 */
    if (PyType_IsSubtype((PyTypeObject *)type, &PyVoidArrType_Type)) {
        // 创建一个新的 _PyArray_LegacyDescr 对象,类型为 NPY_VOID
        _PyArray_LegacyDescr *new = (_PyArray_LegacyDescr  *)PyArray_DescrNewFromType(NPY_VOID);
        if (new == NULL) {
            return NULL;
        }
        // 尝试从 dtype 属性转换为 _PyArray_LegacyDescr 类型
        _PyArray_LegacyDescr *conv = (_PyArray_LegacyDescr *)(
                _arraydescr_try_convert_from_dtype_attr(type));
        if (conv == NULL) {
            Py_DECREF(new);
            return NULL;
        }
        // 如果转换成功且是遗留类型,则复制字段、名称、元素大小和子数组信息
        if ((PyObject *)conv != Py_NotImplemented && PyDataType_ISLEGACY(conv)) {
            new->fields = conv->fields;
            Py_XINCREF(new->fields);
            new->names = conv->names;
            Py_XINCREF(new->names);
            new->elsize = conv->elsize;
            new->subarray = conv->subarray;
            conv->subarray = NULL;
        }
        Py_DECREF(conv);
        Py_XDECREF(new->typeobj);
        // 设置新的 _PyArray_LegacyDescr 的 typeobj 为当前 type 的 PyTypeObject 类型
        new->typeobj = (PyTypeObject *)type;
        Py_INCREF(type);
        // 返回新的 _PyArray_LegacyDescr 类型对象
        return (PyArray_Descr *)new;
    }
    // 否则,调用 _descr_from_subtype 函数处理
    return _descr_from_subtype(type);
/*NUMPY_API
 * 从数组标量对象中获取描述符对象。
 *
 * 返回一个新的引用。
 */
NPY_NO_EXPORT PyArray_Descr *
PyArray_DescrFromScalar(PyObject *sc)
{
    int type_num;  // 声明一个整数变量type_num
    PyArray_Descr *descr;  // 声明一个PyArray_Descr类型的指针descr,用于存储描述符对象的地址

    if (PyArray_IsScalar(sc, Void)) {  // 如果输入的对象是空类型的标量
        descr = (PyArray_Descr *)((PyVoidScalarObject *)sc)->descr;  // 获取空类型标量对象中的描述符对象
        Py_INCREF(descr);  // 增加描述符对象的引用计数
        return descr;  // 返回描述符对象
    }

    if (PyArray_IsScalar(sc, Datetime) || PyArray_IsScalar(sc, Timedelta)) {
        PyArray_DatetimeMetaData *dt_data;  // 声明一个PyArray_DatetimeMetaData类型的指针dt_data

        if (PyArray_IsScalar(sc, Datetime)) {
            descr = PyArray_DescrNewFromType(NPY_DATETIME);  // 如果是日期时间类型的标量,创建一个日期时间描述符对象
        }
        else {
            /* Timedelta */
            descr = PyArray_DescrNewFromType(NPY_TIMEDELTA);  // 如果是时间增量类型的标量,创建一个时间增量描述符对象
        }
        if (descr == NULL) {  // 如果描述符对象创建失败
            return NULL;  // 返回空指针
        }
        dt_data = &(((PyArray_DatetimeDTypeMetaData *)((_PyArray_LegacyDescr *)descr)->c_metadata)->meta);  // 获取日期时间数据元数据
        memcpy(dt_data, &((PyDatetimeScalarObject *)sc)->obmeta, sizeof(PyArray_DatetimeMetaData));  // 复制标量对象中的日期时间元数据到描述符对象中

        return descr;  // 返回描述符对象
    }

    descr = PyArray_DescrFromTypeObject((PyObject *)Py_TYPE(sc));  // 从类型对象中获取描述符对象
    if (descr == NULL) {  // 如果获取描述符对象失败
        return NULL;  // 返回空指针
    }
    if (PyDataType_ISLEGACY(descr) && PyDataType_ISUNSIZED(descr)) {  // 如果描述符对象是遗留类型且未定义大小
        PyArray_DESCR_REPLACE(descr);  // 替换描述符对象
        if (descr == NULL) {  // 如果描述符对象替换失败
            return NULL;  // 返回空指针
        }
        type_num = descr->type_num;  // 获取描述符对象的类型编号
        if (type_num == NPY_STRING) {  // 如果是字符串类型
            descr->elsize = PyBytes_GET_SIZE(sc);  // 获取字节大小
        }
        else if (type_num == NPY_UNICODE) {  // 如果是Unicode类型
            descr->elsize = PyUnicode_GET_LENGTH(sc) * 4;  // 获取Unicode字符的字节大小
        }
        else {
            _PyArray_LegacyDescr *ldescr = (_PyArray_LegacyDescr *)descr;  // 强制转换为遗留描述符对象类型
            PyArray_Descr *dtype;  // 声明一个PyArray_Descr类型的指针dtype
            dtype = (PyArray_Descr *)PyObject_GetAttrString(sc, "dtype");  // 从对象中获取dtype属性
            if (dtype != NULL) {  // 如果获取dtype属性成功
                descr->elsize = dtype->elsize;  // 获取dtype对象的元素大小
                ldescr->fields = PyDataType_FIELDS(dtype);  // 获取字段信息
                Py_XINCREF(ldescr->fields);  // 增加字段信息的引用计数
                ldescr->names = PyDataType_NAMES(dtype);  // 获取字段名信息
                Py_XINCREF(ldescr->names);  // 增加字段名信息的引用计数
                Py_DECREF(dtype);  // 释放dtype对象的引用
            }
            PyErr_Clear();  // 清除异常状态
        }
    }
    return descr;  // 返回描述符对象
}

/*NUMPY_API
 * 根据类型编号获取类型对象 -- 可能返回空值。
 *
 * 返回一个新的引用。
 */
NPY_NO_EXPORT PyObject *
PyArray_TypeObjectFromType(int type)
{
    PyArray_Descr *descr;  // 声明一个PyArray_Descr类型的指针descr
    PyObject *obj;  // 声明一个PyObject类型的指针obj

    descr = PyArray_DescrFromType(type);  // 根据类型编号获取描述符对象
    if (descr == NULL) {  // 如果获取描述符对象失败
        return NULL;  // 返回空指针
    }
    obj = (PyObject *)descr->typeobj;  // 获取描述符对象的类型对象
    Py_XINCREF(obj);  // 增加类型对象的引用计数
    Py_DECREF(descr);  // 释放描述符对象的引用
    return obj;  // 返回类型对象
}

/* 不对descr做任何操作(不会为NULL) */
/*NUMPY_API
  获取描述符描述的内存区域的标量等效对象。
*/
NPY_NO_EXPORT PyObject *
PyArray_Scalar(void *data, PyArray_Descr *descr, PyObject *base)
{
    PyTypeObject *type;  // 声明一个PyTypeObject类型的指针type
    PyObject *obj;  // 声明一个PyObject类型的指针obj
    void *destptr;  // 声明一个void类型的指针destptr
    PyArray_CopySwapFunc *copyswap;  // 声明一个PyArray_CopySwapFunc类型的指针copyswap
    int type_num;  // 声明一个整数变量type_num
    int itemsize;  // 声明一个整数变量itemsize
    int swap;  // 声明一个整数变量swap

    type_num = descr->type_num;  // 获取描述符对象的类型编号
    # 如果数据类型是布尔类型
    if (type_num == NPY_BOOL) {
        # 返回一个布尔值,从数据中获取
        PyArrayScalar_RETURN_BOOL_FROM_LONG(*(npy_bool*)data);
    }
    # 如果数据类型描述符包含 NPY_USE_GETITEM 标志
    else if (PyDataType_FLAGCHK(descr, NPY_USE_GETITEM)) {
        # 使用描述符对应的获取数组函数获取数据
        return PyDataType_GetArrFuncs(descr)->getitem(data, base);
    }
    # 获取元素大小
    itemsize = descr->elsize;
    # 获取数据交换函数
    copyswap = PyDataType_GetArrFuncs(descr)->copyswap;
    # 获取数据类型对象
    type = descr->typeobj;
    # 判断是否需要交换字节序
    swap = !PyArray_ISNBO(descr->byteorder);
    # 如果数据类型是字符串类型
    if (PyTypeNum_ISSTRING(type_num)) {
        /* 消除空字符 */
        char *dptr = data;

        # 将指针移动到字符串末尾
        dptr += itemsize - 1;
        # 如果末尾是空字符,向前移动指针直到非空字符为止
        while(itemsize && *dptr-- == 0) {
            itemsize--;
        }
        # 如果数据类型是 Unicode 并且字符串长度大于 0
        if (type_num == NPY_UNICODE && itemsize) {
            /*
             * 确保字符串长度是4的倍数
             * 向上舍入到最接近的倍数
             */
            itemsize = (((itemsize - 1) >> 2) + 1) << 2;
        }
    }
    # 如果数据类型是 Unicode 类型
    if (type_num == NPY_UNICODE) {
        /* 在这里需要完整的字符串长度,否则 copyswap 将写入过多的字节 */
        # 分配缓冲区
        void *buff = PyArray_malloc(descr->elsize);
        # 如果分配失败,返回内存错误
        if (buff == NULL) {
            return PyErr_NoMemory();
        }
        /* copyswap 需要一个数组对象,但实际上只关心数据类型 */
        # 如果基对象为空,创建一个虚拟数组对象作为基对象
        PyArrayObject_fields dummy_arr;
        if (base == NULL) {
            dummy_arr.descr = descr;
            base = (PyObject *)&dummy_arr;
        }
        # 执行数据交换
        copyswap(buff, data, swap, base);

        /* 截断发生在这里 */
        # 根据 buff 中的数据创建 Unicode 对象
        PyObject *u = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buff, itemsize / 4);
        # 释放缓冲区内存
        PyArray_free(buff);
        # 如果创建 Unicode 对象失败,返回空
        if (u == NULL) {
            return NULL;
        }

        # 构建一个参数元组
        PyObject *args = Py_BuildValue("(O)", u);
        # 如果构建参数元组失败,释放 Unicode 对象并返回空
        if (args == NULL) {
            Py_DECREF(u);
            return NULL;
        }
        # 使用类型对象的 tp_new 方法创建对象
        obj = type->tp_new(type, args, NULL);
        # 释放 Unicode 对象和参数元组的引用
        Py_DECREF(u);
        Py_DECREF(args);
        # 返回创建的对象
        return obj;
    }
    # 如果数据类型的 tp_itemsize 不为 0
    if (type->tp_itemsize != 0) {
        /* 字符串类型 */
        # 使用类型的 tp_alloc 方法分配对象
        obj = type->tp_alloc(type, itemsize);
    }
    else {
        # 否则,使用类型的 tp_alloc 方法分配对象
        obj = type->tp_alloc(type, 0);
    }
    # 如果分配对象失败,返回空
    if (obj == NULL) {
        return NULL;
    }
    # 如果数据类型是日期时间类型
    if (PyTypeNum_ISDATETIME(type_num)) {
        /*
         * 我们需要将分辨率信息复制到标量中
         * 从元数据字典中获取 void * 指针
         */
        # 获取日期时间元数据
        PyArray_DatetimeMetaData *dt_data;

        # 强制转换描述符类型,并获取元数据中的日期时间数据
        dt_data = &(((PyArray_DatetimeDTypeMetaData *)((_PyArray_LegacyDescr *)descr)->c_metadata)->meta);
        # 将日期时间数据复制到标量对象的元数据中
        memcpy(&(((PyDatetimeScalarObject *)obj)->obmeta), dt_data,
               sizeof(PyArray_DatetimeMetaData));
    }
    if (PyTypeNum_ISFLEXIBLE(type_num)) {
        // 检查是否是灵活类型(即字符串或对象)
        if (type_num == NPY_STRING) {
            // 如果是字符串类型,则获取其字符数据指针
            destptr = PyBytes_AS_STRING(obj);
            // 在Python版本低于3.11.0b0时,重置字符串对象的哈希值
            #if PY_VERSION_HEX < 0x030b00b0
                ((PyBytesObject *)obj)->ob_shash = -1;
            #endif
            // 将数据内容复制到字符串对象中
            memcpy(destptr, data, itemsize);
            // 返回修改后的对象
            return obj;
        }
        else {
            // 对于非字符串类型,获取其指针对象
            PyVoidScalarObject *vobj = (PyVoidScalarObject *)obj;
            // 清空对象的基类和描述符,设置为传入的描述符
            vobj->base = NULL;
            vobj->descr = (_PyArray_LegacyDescr *)descr;
            // 增加描述符的引用计数
            Py_INCREF(descr);
            // 清空对象的值,并设置其大小为传入的itemsize
            vobj->obval = NULL;
            Py_SET_SIZE(vobj, itemsize);
            // 设置对象的标志为C连续存储、F顺序存储和拥有数据标志
            vobj->flags = NPY_ARRAY_CARRAY | NPY_ARRAY_F_CONTIGUOUS | NPY_ARRAY_OWNDATA;
            // 默认不进行数据交换
            swap = 0;
            // 如果描述符包含字段信息
            if (PyDataType_HASFIELDS(descr)) {
                // 如果有基类存在,则设置基类信息,并且不拥有数据标志位清除
                if (base) {
                    // 增加基类的引用计数
                    Py_INCREF(base);
                    vobj->base = base;
                    // 获取基类的标志位
                    vobj->flags = PyArray_FLAGS((PyArrayObject *)base);
                    vobj->flags &= ~NPY_ARRAY_OWNDATA;
                    // 设置对象的值为传入的数据指针
                    vobj->obval = data;
                    // 返回修改后的对象
                    return obj;
                }
            }
            // 如果itemsize为0,则直接返回对象
            if (itemsize == 0) {
                return obj;
            }
            // 分配新的内存空间作为对象的值
            destptr = PyDataMem_NEW(itemsize);
            // 如果内存分配失败,则释放对象并返回内存错误异常
            if (destptr == NULL) {
                Py_DECREF(obj);
                return PyErr_NoMemory();
            }
            // 设置对象的值为新分配的内存空间
            vobj->obval = destptr;

            /*
             * 没有基类可用于复制交换,也不需要进行交换。
             * 直接将数据复制到目标中。
             */
            // 如果没有提供基类,则直接复制数据到目标中
            if (base == NULL) {
                memcpy(destptr, data, itemsize);
                // 返回修改后的对象
                return obj;
            }
        }
    }
    else {
        // 对于非灵活类型,使用标量值函数获取对象的值
        destptr = scalar_value(obj, descr);
    }
    /* 对象类型为OBJECT时,复制交换操作会增加引用计数 */
    // 调用复制交换函数对目标进行数据交换操作
    copyswap(destptr, data, swap, base);
    // 返回修改后的对象
    return obj;
/* 返回数组标量,如果遇到0维数组对象 */

/* NUMPY_API
 *
 * 如果数组是0维且匹配Python类型,则返回数组或适当的Python对象。
 * 对于0维数组,如果匹配Python类型,则释放对mp的引用。
 */
NPY_NO_EXPORT PyObject *
PyArray_Return(PyArrayObject *mp)
{
    // 如果传入的数组对象为空,则返回空
    if (mp == NULL) {
        return NULL;
    }
    // 如果发生了异常,释放对mp的引用并返回空
    if (PyErr_Occurred()) {
        Py_XDECREF(mp);
        return NULL;
    }
    // 如果mp不是数组对象,则直接返回mp
    if (!PyArray_Check(mp)) {
        return (PyObject *)mp;
    }
    // 如果数组是0维的
    if (PyArray_NDIM(mp) == 0) {
        // 将数组的数据转换为标量对象,并返回标量对象,同时释放对mp的引用
        PyObject *ret;
        ret = PyArray_ToScalar(PyArray_DATA(mp), mp);
        Py_DECREF(mp);
        return ret;
    }
    else {
        // 如果数组不是0维的,则直接返回mp
        return (PyObject *)mp;
    }
}

.\numpy\numpy\_core\src\multiarray\scalartypes.h

#ifndef NUMPY_CORE_SRC_MULTIARRAY_SCALARTYPES_H_
#define NUMPY_CORE_SRC_MULTIARRAY_SCALARTYPES_H_

/*
 * Internal look-up tables, casting safety is defined in convert_datatype.h.
 * Most of these should be phased out eventually, but some are still used.
 */

// 声明一个外部的静态数组,用于存储标量类型的种类,大小为 NPY_NTYPES_LEGACY
extern NPY_NO_EXPORT signed char
_npy_scalar_kinds_table[NPY_NTYPES_LEGACY];

// 声明一个外部的静态二维数组,用于存储类型提升规则,大小为 NPY_NTYPES_LEGACY x NPY_NTYPES_LEGACY
extern NPY_NO_EXPORT signed char
_npy_type_promotion_table[NPY_NTYPES_LEGACY][NPY_NTYPES_LEGACY];

// 声明一个外部的静态数组,用于存储每种标量类型的最小类型,大小为 NPY_NSCALARKINDS
extern NPY_NO_EXPORT signed char
_npy_smallest_type_of_kind_table[NPY_NSCALARKINDS];

// 声明一个外部的静态数组,用于存储每种类型的下一个更大的类型,大小为 NPY_NTYPES_LEGACY
extern NPY_NO_EXPORT signed char
_npy_next_larger_type_table[NPY_NTYPES_LEGACY];

// 声明一个不导出的函数,用于初始化转换表格
NPY_NO_EXPORT void
initialize_casting_tables(void);

// 声明一个不导出的函数,用于初始化数值类型
NPY_NO_EXPORT void
initialize_numeric_types(void);

// 声明一个不导出的函数,用于释放 gen-type 结构
NPY_NO_EXPORT void
gentype_struct_free(PyObject *ptr);

// 声明一个不导出的函数,用于检查是否是精确的任意标量对象
NPY_NO_EXPORT int
is_anyscalar_exact(PyObject *obj);

// 声明一个不导出的函数,根据类型对象获取类型编号
NPY_NO_EXPORT int
_typenum_fromtypeobj(PyObject *type, int user);

// 声明一个不导出的函数,用于获取标量对象的值并根据描述符转换为适当类型的指针
NPY_NO_EXPORT void *
scalar_value(PyObject *scalar, PyArray_Descr *descr);

#endif  /* NUMPY_CORE_SRC_MULTIARRAY_SCALARTYPES_H_ */


这段代码是一个 C/C++ 的头文件,其中定义了一些静态数组和函数声明,用于管理和处理 NumPy 数组库中标量类型的内部细节和操作。

.\numpy\numpy\_core\src\multiarray\sequence.c

/* 定义以 NPY_API_VERSION 为基准的 NumPy 废弃 API 版本 */
#define NPY_NO_DEPRECATED_API NPY_API_VERSION

/* 定义 _MULTIARRAYMODULE,可能用于标识多维数组模块 */
#define _MULTIARRAYMODULE

/* 清除 PY_SSIZE_T_CLEAN,确保 Py_ssize_t 被定义正确 */
#define PY_SSIZE_T_CLEAN

/* 引入 Python.h 头文件,提供 Python C API 的核心功能 */
#include <Python.h>

/* 引入 structmember.h 头文件,用于定义结构体成员和属性 */
#include <structmember.h>

/* 引入 NumPy 数组对象的头文件 */
#include "numpy/arrayobject.h"

/* 引入 NumPy 数组标量的头文件 */
#include "numpy/arrayscalars.h"

/* 引入 NumPy 配置文件的头文件 */
#include "npy_config.h"

/* 引入公共功能的头文件 */
#include "common.h"

/* 引入映射功能的头文件 */
#include "mapping.h"

/* 引入序列功能的头文件 */
#include "sequence.h"

/* 引入计算功能的头文件 */
#include "calculation.h"

/*************************************************************************
 ****************   实现序列协议 Implement Sequence Protocol **************************
 *************************************************************************/

/* 
   一些内容在 array_as_mapping 协议中也有重复。但是
   我们在这里填写它,以便 PySequence_XXXX 调用按预期工作
*/

/* 
   检查数组是否包含指定元素 el。
   相当于 (self == el).any() 的操作
*/
static int
array_contains(PyArrayObject *self, PyObject *el)
{
    int ret;
    PyObject *res, *any;

    /* 确保将 self 和 el 作为 PyObject 比较,并返回比较结果 */
    res = PyArray_EnsureAnyArray(PyObject_RichCompare((PyObject *)self,
                                                      el, Py_EQ));
    if (res == NULL) {
        return -1;
    }

    /* 对 res 应用 any 函数,检查是否存在非零元素 */
    any = PyArray_Any((PyArrayObject *)res, NPY_RAVEL_AXIS, NULL);
    Py_DECREF(res);
    if (any == NULL) {
        return -1;
    }

    /* 检查 any 对象是否为真 */
    ret = PyObject_IsTrue(any);
    Py_DECREF(any);
    return ret;
}

/* 
   尝试对数组进行连接操作时,抛出类型错误。
   注意:在 PyPy 上运行时,不会抛出此错误。
*/
static PyObject *
array_concat(PyObject *self, PyObject *other)
{
    PyErr_SetString(PyExc_TypeError,
            "Concatenation operation is not implemented for NumPy arrays, "
            "use np.concatenate() instead. Please do not rely on this error; "
            "it may not be given on all Python implementations.");
    return NULL;
}

/* 定义序列协议方法 */
NPY_NO_EXPORT PySequenceMethods array_as_sequence = {
    (lenfunc)array_length,                  /* sq_length */
    (binaryfunc)array_concat,               /* sq_concat for operator.concat */
    (ssizeargfunc)NULL,                     /* sq_repeat */
    (ssizeargfunc)array_item,               /* sq_item */
    (ssizessizeargfunc)NULL,                /* sq_slice */
    (ssizeobjargproc)array_assign_item,     /* sq_ass_item */
    (ssizessizeobjargproc)NULL,             /* sq_ass_slice */
    (objobjproc) array_contains,            /* sq_contains */
    (binaryfunc) NULL,                      /* sq_inplace_concat */
    (ssizeargfunc)NULL                      /* sq_inplace_repeat */
};

.\numpy\numpy\_core\src\multiarray\sequence.h

#ifndef NUMPY_CORE_SRC_MULTIARRAY_SEQUENCE_H_
#define NUMPY_CORE_SRC_MULTIARRAY_SEQUENCE_H_

// 定义条件编译指令,防止头文件重复包含
// 如果 NUMPY_CORE_SRC_MULTIARRAY_SEQUENCE_H_ 宏未定义,则执行下面的内容

// 声明外部链接的 PySequenceMethods 结构体变量 array_as_sequence
extern NPY_NO_EXPORT PySequenceMethods array_as_sequence;

// 结束条件编译指令块
#endif  /* NUMPY_CORE_SRC_MULTIARRAY_SEQUENCE_H_ */

.\numpy\numpy\_core\src\multiarray\shape.c

/* 定义 NPY_NO_DEPRECATED_API 为 NPY_API_VERSION */
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
/* 定义 _MULTIARRAYMODULE */

#define _MULTIARRAYMODULE

/* 定义 PY_SSIZE_T_CLEAN */
#define PY_SSIZE_T_CLEAN

/* 包含 Python 标准头文件 */
#include <Python.h>
/* 包含结构成员的头文件 */
#include <structmember.h>

/* 包含 NumPy 数组对象的头文件 */
#include "numpy/arrayobject.h"
/* 包含 NumPy 数组标量的头文件 */
#include "numpy/arrayscalars.h"

/* 包含 NumPy 的数学函数头文件 */
#include "numpy/npy_math.h"

/* 包含 NumPy 配置文件头文件 */
#include "npy_config.h"

/* 包含数组包装相关的头文件 */
#include "arraywrap.h"
/* 包含构造函数相关的头文件 */
#include "ctors.h"

/* 包含数组形状相关的头文件 */
#include "shape.h"

/* 包含 NumPy 的静态数据头文件,用于内部化字符串 */
#include "npy_static_data.h"

/* 包含模板通用函数头文件,用于 npy_mul_sizes_with_overflow */
#include "templ_common.h"

/* 包含通用函数头文件,用于 convert_shape_to_string */
#include "common.h"

/* 包含分配相关的头文件 */
#include "alloc.h"

/* 定义修复未知维度的静态函数 */
static int
_fix_unknown_dimension(PyArray_Dims *newshape, PyArrayObject *arr);

/* 定义尝试无拷贝重塑的静态函数 */
static int
_attempt_nocopy_reshape(PyArrayObject *self, int newnd, const npy_intp *newdims,
                        npy_intp *newstrides, int is_f_order);

/* 定义将零值放入指定位置的静态函数 */
static void
_putzero(char *optr, PyObject *zero, PyArray_Descr *dtype);

/* NUMPY_API
 * 调整大小(重新分配数据)。仅在数组是单一段且没有其他引用的情况下才有效。
 * 如果 refcheck 是 0,则不检查引用计数,假设引用计数为 1。
 * 仍然需要拥有数据并且没有弱引用和基对象。
 */
NPY_NO_EXPORT PyObject *
PyArray_Resize(PyArrayObject *self, PyArray_Dims *newshape, int refcheck,
               NPY_ORDER NPY_UNUSED(order))
{
    npy_intp oldnbytes, newnbytes;
    npy_intp oldsize, newsize;
    int new_nd = newshape->len, k, elsize;
    int refcnt;
    npy_intp* new_dimensions = newshape->ptr;
    npy_intp new_strides[NPY_MAXDIMS];
    npy_intp *dimptr;
    char *new_data;

    /* 如果数组不是单一段,报错并返回空指针 */
    if (!PyArray_ISONESEGMENT(self)) {
        PyErr_SetString(PyExc_ValueError,
                "resize only works on single-segment arrays");
        return NULL;
    }

    /* 计算旧数组和新数组的总大小。新大小可能会溢出 */
    oldsize = PyArray_SIZE(self);
    newsize = 1;
    for(k = 0; k < new_nd; k++) {
        /* 如果维度为 0,则新大小为 0 */
        if (new_dimensions[k] == 0) {
            newsize = 0;
            break;
        }
        /* 如果维度为负数,报错并返回空指针 */
        if (new_dimensions[k] < 0) {
            PyErr_SetString(PyExc_ValueError,
                    "negative dimensions not allowed");
            return NULL;
        }
        /* 计算新大小,防止溢出 */
        if (npy_mul_sizes_with_overflow(&newsize, newsize, new_dimensions[k])) {
            return PyErr_NoMemory();
        }
    }

    /* 将大小转换为字节数。新的计数可能会溢出 */
    elsize = PyArray_ITEMSIZE(self);
    oldnbytes = oldsize * elsize;
    if (npy_mul_sizes_with_overflow(&newnbytes, newsize, elsize)) {
        return PyErr_NoMemory();
    }
    # 如果旧字节大小不等于新字节大小,则执行以下代码块
    if (oldnbytes != newnbytes) {
        # 如果数组不拥有自己的数据(即不是内存所有者),则抛出数值错误异常并返回空
        if (!(PyArray_FLAGS(self) & NPY_ARRAY_OWNDATA)) {
            PyErr_SetString(PyExc_ValueError,
                    "cannot resize this array: it does not own its data");
            return NULL;
        }

        # 如果数组有基础对象(base)或者有弱引用列表,则抛出数值错误异常并返回空
        if (PyArray_BASE(self) != NULL
              || (((PyArrayObject_fields *)self)->weakreflist != NULL)) {
            PyErr_SetString(PyExc_ValueError,
                    "cannot resize an array that "
                    "references or is referenced\n"
                    "by another array in this way. Use the np.resize function.");
            return NULL;
        }
        
        # 如果启用了引用检查(refcheck 参数为真),则执行以下代码块
        if (refcheck) {
#ifdef PYPY_VERSION
            /* 如果在 PyPy 上且 refcheck=True,则不能调整数组大小 */
            PyErr_SetString(PyExc_ValueError,
                    "cannot resize an array with refcheck=True on PyPy.\n"
                    "Use the np.resize function or refcheck=False");
            return NULL;
#else
            /* 否则获取对象的引用计数 */
            refcnt = Py_REFCNT(self);
#endif /* PYPY_VERSION */
        }
        else {
            /* 对于不可变对象,引用计数为 1 */
            refcnt = 1;
        }
        if (refcnt > 2) {
            /* 如果引用计数大于 2,则无法调整大小 */
            PyErr_SetString(PyExc_ValueError,
                    "cannot resize an array that "
                    "references or is referenced\n"
                    "by another array in this way.\n"
                    "Use the np.resize function or refcheck=False");
            return NULL;
        }

        /* 如果需要重新分配空间,则进行重新分配 - 分配 0 大小被禁止 */
        PyObject *handler = PyArray_HANDLER(self);
        if (handler == NULL) {
            /* 如果没有找到内存处理器但设置了 NPY_ARRAY_OWNDATA 标志,则报错 */
            PyErr_SetString(PyExc_RuntimeError,
                            "no memory handler found but OWNDATA flag set");
            return NULL;
        }
        /* 使用 PyDataMem_UserRENEW 重新分配数据 */
        new_data = PyDataMem_UserRENEW(PyArray_DATA(self),
                                       newnbytes == 0 ? elsize : newnbytes,
                                       handler);
        if (new_data == NULL) {
            /* 如果无法分配内存,则报内存错误 */
            PyErr_SetString(PyExc_MemoryError,
                    "cannot allocate memory for array");
            return NULL;
        }
        /* 更新数组对象的数据指针 */
        ((PyArrayObject_fields *)self)->data = new_data;
    }

    /* 如果新分配的大小大于旧大小且数组可写,则填充新分配的内存区域为零 */
    if (newnbytes > oldnbytes && PyArray_ISWRITEABLE(self)) {
        /* 如果数组的数据类型包含引用计数,则使用 _putzero 函数填充 */
        if (PyDataType_FLAGCHK(PyArray_DESCR(self), NPY_ITEM_REFCOUNT)) {
            PyObject *zero = PyLong_FromLong(0);
            char *optr;
            /* 指向新内存的起始位置 */
            optr = PyArray_BYTES(self) + oldnbytes;
            /* 计算需要填充零的元素数量 */
            npy_intp n_new = newsize - oldsize;
            /* 循环填充零 */
            for (npy_intp i = 0; i < n_new; i++) {
                _putzero((char *)optr, zero, PyArray_DESCR(self));
                optr += elsize;
            }
            /* 释放零对象 */
            Py_DECREF(zero);
        }
        else {
            /* 否则使用 memset 函数填充零 */
            memset(PyArray_BYTES(self) + oldnbytes, 0, newnbytes - oldnbytes);
        }
    }
    # 如果新的维度数大于零,则需要进行维度和步长的调整
    if (new_nd > 0) {
        # 如果当前数组的维度数与新的维度数不同
        if (PyArray_NDIM(self) != new_nd) {
            /* 不同的维度数。*/
            # 更新数组对象的维度数为新的维度数
            ((PyArrayObject_fields *)self)->nd = new_nd;
            /* 需要新的维度和步长数组 */
            # 重新分配维度和步长数组的内存空间
            dimptr = PyDimMem_RENEW(PyArray_DIMS(self), 3*new_nd);
            # 如果内存分配失败
            if (dimptr == NULL) {
                # 报告内存错误
                PyErr_SetString(PyExc_MemoryError,
                                "cannot allocate memory for array");
                return NULL;
            }
            # 更新数组对象的维度和步长指针
            ((PyArrayObject_fields *)self)->dimensions = dimptr;
            ((PyArrayObject_fields *)self)->strides = dimptr + new_nd;
        }
        /* 生成新的步长变量 */
        # 填充新的步长数组
        _array_fill_strides(new_strides, new_dimensions, new_nd,
                            PyArray_ITEMSIZE(self), PyArray_FLAGS(self),
                            &(((PyArrayObject_fields *)self)->flags));
        # 移动新维度数据到数组对象的维度数组中
        memmove(PyArray_DIMS(self), new_dimensions, new_nd*sizeof(npy_intp));
        # 移动新步长数据到数组对象的步长数组中
        memmove(PyArray_STRIDES(self), new_strides, new_nd*sizeof(npy_intp));
    }
    else {
        # 如果新的维度数不大于零,则清理数组对象的维度和步长数组
        PyDimMem_FREE(((PyArrayObject_fields *)self)->dimensions);
        ((PyArrayObject_fields *)self)->nd = 0;
        ((PyArrayObject_fields *)self)->dimensions = NULL;
        ((PyArrayObject_fields *)self)->strides = NULL;
    }
    # 返回 None
    Py_RETURN_NONE;
/*
 * 返回一个新的数组
 * 根据旧数组的数据和顺序参数创建具有新形状的数组
 * 只在必要时复制数据
 */

/*NUMPY_API
 * 为数组创建新形状
 */
NPY_NO_EXPORT PyObject *
PyArray_Newshape(PyArrayObject *self, PyArray_Dims *newdims,
                 NPY_ORDER order)
{
    // 调用内部函数进行重塑,根据需要复制数据
    return _reshape_with_copy_arg(self, newdims, order, NPY_COPY_IF_NEEDED);
}


NPY_NO_EXPORT PyObject *
_reshape_with_copy_arg(PyArrayObject *array, PyArray_Dims *newdims,
                       NPY_ORDER order, NPY_COPYMODE copy)
{
    npy_intp i;
    npy_intp *dimensions = newdims->ptr;  // 新形状的维度数组
    PyArrayObject *ret;  // 返回的重塑后的数组对象
    int ndim = newdims->len;  // 新形状的维度数
    npy_bool same;  // 标志变量,表示新旧形状是否相同
    npy_intp *strides = NULL;  // 步长数组,默认为空
    npy_intp newstrides[NPY_MAXDIMS];  // 新数组的步长数组
    int flags;  // 标志变量

    // 如果顺序为 NPY_ANYORDER,则根据数组是否为 Fortran 风格或 C 风格决定顺序
    if (order == NPY_ANYORDER) {
        order = PyArray_ISFORTRAN(array) ? NPY_FORTRANORDER : NPY_CORDER;
    }
    // 如果顺序为 NPY_KEEPORDER,不允许使用 'K' 来进行重塑,抛出异常
    else if (order == NPY_KEEPORDER) {
        PyErr_SetString(PyExc_ValueError,
                "order 'K' is not permitted for reshaping");
        return NULL;
    }
    // 快速检查是否需要执行重塑操作
    if (ndim == PyArray_NDIM(array) && copy != NPY_COPY_ALWAYS) {
        same = NPY_TRUE;
        i = 0;
        while (same && i < ndim) {
            // 检查每个维度是否相同
            if (PyArray_DIM(array, i) != dimensions[i]) {
                same = NPY_FALSE;
            }
            i++;
        }
        // 如果形状相同,则返回数组的视图
        if (same) {
            return PyArray_View(array, NULL, NULL);
        }
    }

    /*
     * 修正任何 -1 的维度,并检查新形状与旧数组大小的匹配情况
     */
    if (_fix_unknown_dimension(newdims, array) < 0) {
        return NULL;
    }
    /*
     * 内存顺序不依赖于复制/非复制的上下文
     * 始终根据 'order' 参数决定顺序
     */
    // 如果需要始终复制数据,则创建数组的副本
    if (copy == NPY_COPY_ALWAYS) {
        PyObject *newcopy = PyArray_NewCopy(array, order);
        if (newcopy == NULL) {
            return NULL;
        }
        array = (PyArrayObject *)newcopy;
    }
    else {
        /*
         * 有时我们必须创建数组的新副本
         * 以便获取正确的方向和
         * 因为我们不能简单地重用带有
         * 数据顺序的缓冲区。
         */
        Py_INCREF(array);  // 增加数组的引用计数,以防止其被意外释放
        if (((order == NPY_CORDER && !PyArray_IS_C_CONTIGUOUS(array)) ||
                (order == NPY_FORTRANORDER && !PyArray_IS_F_CONTIGUOUS(array)))) {
            int success = 0;
            success = _attempt_nocopy_reshape(array, ndim, dimensions,
                                              newstrides, order);
            if (success) {
                /* 原地重塑成功,不需要复制数组 */
                strides = newstrides;  // 更新步幅为新计算的步幅
            }
            else if (copy == NPY_COPY_NEVER) {
                PyErr_SetString(PyExc_ValueError,
                                "Unable to avoid creating a copy while reshaping.");
                Py_DECREF(array);  // 减少数组的引用计数
                return NULL;  // 返回空指针表示错误
            }
            else {
                PyObject *newcopy = PyArray_NewCopy(array, order);
                Py_DECREF(array);  // 减少原始数组的引用计数
                if (newcopy == NULL) {
                    return NULL;  // 如果复制失败,返回空指针
                }
                array = (PyArrayObject *)newcopy;  // 更新数组为新复制的数组
            }
        }
    }
    /* 我们总是必须正确地解释连续的缓冲区 */

    /* 确保 flags 参数被设置。*/
    flags = PyArray_FLAGS(array);  // 获取数组的标志位
    if (ndim > 1) {
        if (order == NPY_FORTRANORDER) {
            flags &= ~NPY_ARRAY_C_CONTIGUOUS;  // 清除 C 连续标志位
            flags |= NPY_ARRAY_F_CONTIGUOUS;   // 设置 Fortran 连续标志位
        }
        else {
            flags &= ~NPY_ARRAY_F_CONTIGUOUS;  // 清除 Fortran 连续标志位
            flags |= NPY_ARRAY_C_CONTIGUOUS;   // 设置 C 连续标志位
        }
    }

    Py_INCREF(PyArray_DESCR(array));  // 增加数组描述符的引用计数
    ret = (PyArrayObject *)PyArray_NewFromDescr_int(
            Py_TYPE(array), PyArray_DESCR(array),
            ndim, dimensions, strides, PyArray_DATA(array),
            flags, (PyObject *)array, (PyObject *)array,
            _NPY_ARRAY_ENSURE_DTYPE_IDENTITY);
    Py_DECREF(array);  // 减少数组的引用计数
    return (PyObject *)ret;  // 返回处理后的 Python 对象
/* For backward compatibility -- Not recommended */
/*NUMPY_API
 * Reshape
 */
/* 定义 PyArray_Reshape 函数,用于对数组进行重新形状化操作 */
NPY_NO_EXPORT PyObject *
PyArray_Reshape(PyArrayObject *self, PyObject *shape)
{
    PyObject *ret;
    PyArray_Dims newdims;

    /* 使用 PyArray_IntpConverter 将 shape 转换为 PyArray_Dims 结构 */
    if (!PyArray_IntpConverter(shape, &newdims)) {
        return NULL;
    }
    /* 调用 PyArray_Newshape 函数重新构造数组的形状 */
    ret = PyArray_Newshape(self, &newdims, NPY_CORDER);
    /* 释放 newdims 占用的内存 */
    npy_free_cache_dim_obj(newdims);
    return ret;
}

/* 定义 _putzero 函数,用于在数组中置零操作 */
static void
_putzero(char *optr, PyObject *zero, PyArray_Descr *dtype)
{
    /* 如果 dtype 不是引用计数类型,则使用 memset 将 optr 置零 */
    if (!PyDataType_FLAGCHK(dtype, NPY_ITEM_REFCOUNT)) {
        memset(optr, 0, dtype->elsize);
    }
    /* 如果 dtype 有字段 */
    else if (PyDataType_HASFIELDS(dtype)) {
        PyObject *key, *value, *title = NULL;
        PyArray_Descr *new;
        int offset;
        Py_ssize_t pos = 0;
        /* 遍历 dtype 的字段 */
        while (PyDict_Next(PyDataType_FIELDS(dtype), &pos, &key, &value)) {
            /* 如果字段是标题字段,则跳过 */
            if (NPY_TITLE_KEY(key, value)) {
                continue;
            }
            /* 解析字段的信息 */
            if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset, &title)) {
                return;
            }
            /* 在 optr + offset 处置零 */
            _putzero(optr + offset, zero, new);
        }
    }
    /* 否则按 dtype 的元素大小置零 */
    else {
        npy_intp i;
        npy_intp nsize = dtype->elsize / sizeof(zero);

        /* 遍历元素并置零 */
        for (i = 0; i < nsize; i++) {
            Py_INCREF(zero);
            memcpy(optr, &zero, sizeof(zero));
            optr += sizeof(zero);
        }
    }
    return;
}

/*
 * attempt to reshape an array without copying data
 *
 * The requested newdims are not checked, but must be compatible with
 * the size of self, which must be non-zero. Other than that this
 * function should correctly handle all reshapes, including axes of
 * length 1. Zero strides should work but are untested.
 *
 * If a copy is needed, returns 0
 * If no copy is needed, returns 1 and fills newstrides
 *     with appropriate strides
 *
 * The "is_f_order" argument describes how the array should be viewed
 * during the reshape, not how it is stored in memory (that
 * information is in PyArray_STRIDES(self)).
 *
 * If some output dimensions have length 1, the strides assigned to
 * them are arbitrary. In the current implementation, they are the
 * stride of the next-fastest index.
 */
/* 定义 _attempt_nocopy_reshape 函数,尝试在不复制数据的情况下重新形状化数组 */
static int
_attempt_nocopy_reshape(PyArrayObject *self, int newnd, const npy_intp *newdims,
                        npy_intp *newstrides, int is_f_order)
{
    int oldnd;
    npy_intp olddims[NPY_MAXDIMS];
    npy_intp oldstrides[NPY_MAXDIMS];
    npy_intp last_stride;
    int oi, oj, ok, ni, nj, nk;

    oldnd = 0;
    /*
     * Remove axes with dimension 1 from the old array. They have no effect
     * but would need special cases since their strides do not matter.
     */
    /* 从旧数组中移除维度为 1 的轴 */
    for (oi = 0; oi < PyArray_NDIM(self); oi++) {
        if (PyArray_DIMS(self)[oi]!= 1) {
            olddims[oldnd] = PyArray_DIMS(self)[oi];
            oldstrides[oldnd] = PyArray_STRIDES(self)[oi];
            oldnd++;
        }
    }

    /* oi to oj and ni to nj give the axis ranges currently worked with */
    oi = 0;
    oj = 1;
    ni = 0;
    nj = 1;
    while (ni < newnd && oi < oldnd) {
        npy_intp np = newdims[ni];  // 获取新维度数组中的当前维度大小
        npy_intp op = olddims[oi];  // 获取旧维度数组中的当前维度大小

        while (np != op) {
            if (np < op) {
                /* Misses trailing 1s, these are handled later */
                np *= newdims[nj++];  // 如果新维度小于旧维度,则将当前维度乘以下一个新维度以处理后续的尾随1
            } else {
                op *= olddims[oj++];  // 否则,将当前维度乘以下一个旧维度
            }
        }

        /* Check whether the original axes can be combined */
        for (ok = oi; ok < oj - 1; ok++) {
            if (is_f_order) {
                if (oldstrides[ok+1] != olddims[ok]*oldstrides[ok]) {
                     /* not contiguous enough */
                    return 0;  // 如果不是足够连续的,返回0
                }
            }
            else {
                /* C order */
                if (oldstrides[ok] != olddims[ok+1]*oldstrides[ok+1]) {
                    /* not contiguous enough */
                    return 0;  // 如果不是足够连续的,返回0
                }
            }
        }

        /* Calculate new strides for all axes currently worked with */
        if (is_f_order) {
            newstrides[ni] = oldstrides[oi];  // 如果是Fortran顺序,则将新步幅设置为旧步幅
            for (nk = ni + 1; nk < nj; nk++) {
                newstrides[nk] = newstrides[nk - 1]*newdims[nk - 1];  // 对于后续的轴,根据前一个轴的步幅和维度计算新步幅
            }
        }
        else {
            /* C order */
            newstrides[nj - 1] = oldstrides[oj - 1];  // 如果是C顺序,则将最后一个新步幅设置为最后一个旧步幅
            for (nk = nj - 1; nk > ni; nk--) {
                newstrides[nk - 1] = newstrides[nk]*newdims[nk];  // 对于前面的轴,根据后一个轴的步幅和维度计算新步幅
            }
        }
        ni = nj++;  // 更新新维度索引并增加下一个新维度索引
        oi = oj++;  // 更新旧维度索引并增加下一个旧维度索引
    }

    /*
     * Set strides corresponding to trailing 1s of the new shape.
     */
    if (ni >= 1) {
        last_stride = newstrides[ni - 1];  // 如果新维度索引大于等于1,设置最后一个步幅为前一个新步幅
    }
    else {
        last_stride = PyArray_ITEMSIZE(self);  // 否则,设置最后一个步幅为数组中的每个元素的大小
    }
    if (is_f_order) {
        last_stride *= newdims[ni - 1];  // 如果是Fortran顺序,根据最后一个新维度调整最后一个步幅
    }
    for (nk = ni; nk < newnd; nk++) {
        newstrides[nk] = last_stride;  // 设置新维度中剩余轴的步幅为最后一个步幅
    }

    return 1;  // 返回成功
}

static void
raise_reshape_size_mismatch(PyArray_Dims *newshape, PyArrayObject *arr)
{
    // 将新形状转换为字符串表示
    PyObject *tmp = convert_shape_to_string(newshape->len, newshape->ptr, "");
    // 如果转换成功
    if (tmp != NULL) {
        // 抛出格式化的 ValueError 异常
        PyErr_Format(PyExc_ValueError,
                "cannot reshape array of size %zd into shape %S",
                PyArray_SIZE(arr), tmp);
        // 释放临时对象
        Py_DECREF(tmp);
    }
}

static int
_fix_unknown_dimension(PyArray_Dims *newshape, PyArrayObject *arr)
{
    npy_intp *dimensions;
    npy_intp s_original = PyArray_SIZE(arr);
    npy_intp i_unknown, s_known;
    int i, n;

    dimensions = newshape->ptr;
    n = newshape->len;
    s_known = 1;
    i_unknown = -1;

    // 遍历新形状的维度数组
    for (i = 0; i < n; i++) {
        // 处理未知维度的情况
        if (dimensions[i] < 0) {
            // 如果已经有未知维度
            if (i_unknown == -1) {
                i_unknown = i;
            }
            else {
                // 抛出值错误异常,只能指定一个未知维度
                PyErr_SetString(PyExc_ValueError,
                                "can only specify one unknown dimension");
                return -1;
            }
        }
        else if (npy_mul_sizes_with_overflow(&s_known, s_known,
                                            dimensions[i])) {
            // 如果计算维度乘积溢出,抛出重塑大小不匹配异常
            raise_reshape_size_mismatch(newshape, arr);
            return -1;
        }
    }

    // 处理存在未知维度的情况
    if (i_unknown >= 0) {
        // 如果已知维度为 0 或者原始数组大小不能整除已知维度
        if (s_known == 0 || s_original % s_known != 0) {
            // 抛出重塑大小不匹配异常
            raise_reshape_size_mismatch(newshape, arr);
            return -1;
        }
        // 计算未知维度的值
        dimensions[i_unknown] = s_original / s_known;
    }
    else {
        // 如果没有未知维度,检查原始大小是否等于已知维度
        if (s_original != s_known) {
            // 抛出重塑大小不匹配异常
            raise_reshape_size_mismatch(newshape, arr);
            return -1;
        }
    }
    return 0;
}

/*NUMPY_API
 *
 * return a new view of the array object with all of its unit-length
 * dimensions squeezed out if needed, otherwise
 * return the same array.
 */
NPY_NO_EXPORT PyObject *
PyArray_Squeeze(PyArrayObject *self)
{
    PyArrayObject *ret;
    npy_bool unit_dims[NPY_MAXDIMS];
    int idim, ndim, any_ones;
    npy_intp *shape;

    // 获取数组的维度数和形状
    ndim = PyArray_NDIM(self);
    shape = PyArray_SHAPE(self);

    any_ones = 0;
    // 遍历数组的每个维度
    for (idim = 0; idim < ndim; ++idim) {
        // 如果维度为 1,则表示为单位维度
        if (shape[idim] == 1) {
            unit_dims[idim] = 1;
            any_ones = 1;
        }
        else {
            unit_dims[idim] = 0;
        }
    }

    /* 如果没有单位维度需要挤压,直接返回原数组 */
    if (!any_ones) {
        // 增加原数组的引用计数并返回
        Py_INCREF(self);
        return (PyObject *)self;
    }

    // 创建数组的视图,去除单位维度
    ret = (PyArrayObject *)PyArray_View(self, NULL, &PyArray_Type);
    // 如果创建视图失败,返回空指针
    if (ret == NULL) {
        return NULL;
    }

    // 在视图中移除指定的单位维度
    PyArray_RemoveAxesInPlace(ret, unit_dims);

    /*
     * 如果 self 不是基类 ndarray,调用其 __array_wrap__ 方法
     */
    if (Py_TYPE(self) != &PyArray_Type) {
        // 应用简单的数组包装方法,并返回包装后的对象
        PyObject *wrapped = npy_apply_wrap_simple(self, ret);
        Py_DECREF(ret);
        return wrapped;
    }

    // 返回视图对象
    return (PyObject *)ret;
}

/*
 * Just like PyArray_Squeeze, but allows the caller to select
 * a subset of the size-one dimensions to squeeze out.
 */
/*
 * Squeeze selected axes in a NumPy array.
 */
NPY_NO_EXPORT PyObject *
PyArray_SqueezeSelected(PyArrayObject *self, npy_bool *axis_flags)
{
    PyArrayObject *ret;
    int idim, ndim, any_ones;
    npy_intp *shape;

    ndim = PyArray_NDIM(self);      // 获取数组的维度数
    shape = PyArray_SHAPE(self);    // 获取数组的形状

    /* Verify that the axes requested are all of size one */
    any_ones = 0;
    for (idim = 0; idim < ndim; ++idim) {
        if (axis_flags[idim] != 0) {    // 如果axis_flags[idim]为真
            if (shape[idim] == 1) {     // 如果该轴的大小为1
                any_ones = 1;           // 设置标志位,表示存在可以压缩的轴
            }
            else {
                PyErr_SetString(PyExc_ValueError,
                        "cannot select an axis to squeeze out "
                        "which has size not equal to one");  // 抛出值错误异常,说明无法压缩大小不为1的轴
                return NULL;    // 返回空指针
            }
        }
    }

    /* If there were no axes to squeeze out, return the same array */
    if (!any_ones) {    // 如果没有需要压缩的轴
        Py_INCREF(self);    // 增加对self的引用计数
        return (PyObject *)self;    // 返回self数组的Python对象指针
    }

    ret = (PyArrayObject *)PyArray_View(self, NULL, &PyArray_Type);    // 创建一个self的视图
    if (ret == NULL) {    // 如果视图创建失败
        return NULL;    // 返回空指针
    }

    PyArray_RemoveAxesInPlace(ret, axis_flags);    // 在ret中就地移除指定的轴

    /*
     * If self isn't not a base class ndarray, call its
     * __array_wrap__ method
     */
    if (Py_TYPE(self) != &PyArray_Type) {    // 如果self不是基类ndarray
        PyObject *wrapped = npy_apply_wrap_simple(self, ret);    // 调用self的__array_wrap__方法
        Py_DECREF(ret);    // 减少对ret的引用计数
        return wrapped;    // 返回调用结果
    }

    return (PyObject *)ret;    // 返回视图ret的Python对象指针
}

/*
 * SwapAxes in a NumPy array.
 */
/*NUMPY_API
 * SwapAxes
 */
NPY_NO_EXPORT PyObject *
PyArray_SwapAxes(PyArrayObject *ap, int a1, int a2)
{
    PyArray_Dims new_axes;
    npy_intp dims[NPY_MAXDIMS];
    int n = PyArray_NDIM(ap);
    int i;

    if (check_and_adjust_axis_msg(&a1, n, npy_interned_str.axis1) < 0) {    // 检查并调整轴a1
        return NULL;    // 返回空指针
    }
    if (check_and_adjust_axis_msg(&a2, n, npy_interned_str.axis2) < 0) {    // 检查并调整轴a2
        return NULL;    // 返回空指针
    }

    for (i = 0; i < n; ++i) {    // 设置初始维度顺序
        dims[i] = i;
    }
    dims[a1] = a2;    // 交换轴a1和a2
    dims[a2] = a1;

    new_axes.ptr = dims;    // 设置新轴顺序
    new_axes.len = n;

    return PyArray_Transpose(ap, &new_axes);    // 返回转置后的数组
}


/*
 * Transpose a NumPy array.
 */
/*NUMPY_API
 * Return Transpose.
 */
NPY_NO_EXPORT PyObject *
PyArray_Transpose(PyArrayObject *ap, PyArray_Dims *permute)
{
    npy_intp *axes;
    int i, n;
    int permutation[NPY_MAXDIMS], reverse_permutation[NPY_MAXDIMS];
    PyArrayObject *ret = NULL;
    int flags;

    if (permute == NULL) {    // 如果未指定置换顺序
        n = PyArray_NDIM(ap);    // 获取数组的维度数
        for (i = 0; i < n; i++) {
            permutation[i] = n-1-i;    // 设置默认逆序置换顺序
        }
    }

    // 更多代码...
}
    else {
        // 获取置换数组的长度和指针
        n = permute->len;
        axes = permute->ptr;
        // 如果长度与数组维度不匹配,设置错误信息并返回空
        if (n != PyArray_NDIM(ap)) {
            PyErr_SetString(PyExc_ValueError,
                            "axes don't match array");
            return NULL;
        }
        // 初始化逆置换数组,全部置为-1
        for (i = 0; i < n; i++) {
            reverse_permutation[i] = -1;
        }
        // 对每个轴进行检查和调整
        for (i = 0; i < n; i++) {
            int axis = axes[i];
            // 检查并调整轴的有效性,若无效则返回空
            if (check_and_adjust_axis(&axis, PyArray_NDIM(ap)) < 0) {
                return NULL;
            }
            // 如果在逆置换数组中发现重复的轴,设置错误信息并返回空
            if (reverse_permutation[axis] != -1) {
                PyErr_SetString(PyExc_ValueError,
                                "repeated axis in transpose");
                return NULL;
            }
            // 更新置换和逆置换数组
            reverse_permutation[axis] = i;
            permutation[i] = axis;
        }
    }

    // 获取数组的标志位
    flags = PyArray_FLAGS(ap);

    /*
     * 分配内存给维度和步幅(但填充不正确),设置描述符,并将数据指向 PyArray_DATA(ap)。
     */
    // 增加描述符的引用计数
    Py_INCREF(PyArray_DESCR(ap));
    // 使用描述符和基础数据创建新的数组对象
    ret = (PyArrayObject *) PyArray_NewFromDescrAndBase(
            Py_TYPE(ap), PyArray_DESCR(ap),
            n, PyArray_DIMS(ap), NULL, PyArray_DATA(ap),
            flags, (PyObject *)ap, (PyObject *)ap);
    // 若创建失败,返回空
    if (ret == NULL) {
        return NULL;
    }

    /* 调整返回数组的维度和步幅 */
    for (i = 0; i < n; i++) {
        // 根据置换数组更新维度
        PyArray_DIMS(ret)[i] = PyArray_DIMS(ap)[permutation[i]];
        // 根据置换数组更新步幅
        PyArray_STRIDES(ret)[i] = PyArray_STRIDES(ap)[permutation[i]];
    }
    // 更新返回数组的标志位
    PyArray_UpdateFlags(ret, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_F_CONTIGUOUS |
                        NPY_ARRAY_ALIGNED);
    // 返回转置后的数组对象
    return (PyObject *)ret;
/*
 * Return matrix transpose (swap last two dimensions).
 */
NPY_NO_EXPORT PyObject *
PyArray_MatrixTranspose(PyArrayObject *ap)
{
    int ndim = PyArray_NDIM(ap); // 获取数组的维度数

    if (ndim < 2) { // 如果维度数小于2,抛出数值错误异常
        PyErr_SetString(PyExc_ValueError,
                        "matrix transpose with ndim < 2 is undefined");
        return NULL;
    }
    return PyArray_SwapAxes(ap, ndim - 2, ndim - 1); // 返回交换了最后两个维度的数组对象
}

/*
 * Sorts items so stride is descending, because C-order
 * is the default in the face of ambiguity.
 */
static int _npy_stride_sort_item_comparator(const void *a, const void *b)
{
    npy_intp astride = ((const npy_stride_sort_item *)a)->stride, // 获取结构体元素 a 的步幅
            bstride = ((const npy_stride_sort_item *)b)->stride; // 获取结构体元素 b 的步幅

    /* Sort the absolute value of the strides */
    if (astride < 0) { // 如果步幅为负数,取其绝对值
        astride = -astride;
    }
    if (bstride < 0) { // 如果步幅为负数,取其绝对值
        bstride = -bstride;
    }

    if (astride == bstride) { // 如果步幅相等,则按照排列顺序比较
        /*
         * Make the qsort stable by next comparing the perm order.
         * (Note that two perm entries will never be equal)
         */
        npy_intp aperm = ((const npy_stride_sort_item *)a)->perm, // 获取结构体元素 a 的排列顺序
                bperm = ((const npy_stride_sort_item *)b)->perm; // 获取结构体元素 b 的排列顺序
        return (aperm < bperm) ? -1 : 1; // 返回根据排列顺序比较的结果
    }
    if (astride > bstride) { // 如果 a 的步幅大于 b 的步幅,返回 -1
        return -1;
    }
    return 1; // 否则返回 1
}

/*NUMPY_API
 *
 * This function populates the first ndim elements
 * of strideperm with sorted descending by their absolute values.
 * For example, the stride array (4, -2, 12) becomes
 * [(2, 12), (0, 4), (1, -2)].
 */
NPY_NO_EXPORT void
PyArray_CreateSortedStridePerm(int ndim, npy_intp const *strides,
                        npy_stride_sort_item *out_strideperm)
{
    int i;

    /* Set up the strideperm values */
    for (i = 0; i < ndim; ++i) { // 初始化 strideperm 结构体数组,设置排列顺序和步幅
        out_strideperm[i].perm = i; // 设置排列顺序为当前索引 i
        out_strideperm[i].stride = strides[i]; // 设置步幅为 strides 数组中对应的值
    }

    /* Sort them */
    qsort(out_strideperm, ndim, sizeof(npy_stride_sort_item),
                                    &_npy_stride_sort_item_comparator); // 使用 qsort 对 strideperm 结构体数组进行排序
}

static inline npy_intp
s_intp_abs(npy_intp x)
{
    return (x < 0) ? -x : x; // 返回 x 的绝对值
}

/*
 * Creates a sorted stride perm matching the KEEPORDER behavior
 * of the NpyIter object. Because this operates based on multiple
 * input strides, the 'stride' member of the npy_stride_sort_item
 * would be useless and we simply argsort a list of indices instead.
 *
 * The caller should have already validated that 'ndim' matches for
 * every array in the arrays list.
 */
NPY_NO_EXPORT void
PyArray_CreateMultiSortedStridePerm(int narrays, PyArrayObject **arrays,
                        int ndim, int *out_strideperm)
{
    int i0, i1, ipos, ax_j0, ax_j1, iarrays;

    /* Initialize the strideperm values to the identity. */
    for (i0 = 0; i0 < ndim; ++i0) { // 初始化 strideperm 数组,使其对应于标识
        out_strideperm[i0] = i0; // 设置当前索引处的值为当前索引 i0
    }
}
    /*
     * 这段代码实现了一种定制的稳定插入排序,用于NpyIter对象,但以与迭代器相反的顺序排序。
     * 迭代器按照最小步长到最大步长的顺序排序(Fortran顺序),而这里按照最大步长到最小步长的顺序排序(C顺序)。
     */
    for (i0 = 1; i0 < ndim; ++i0) {

        ipos = i0;
        ax_j0 = out_strideperm[i0];

        for (i1 = i0 - 1; i1 >= 0; --i1) {
            int ambig = 1, shouldswap = 0;

            ax_j1 = out_strideperm[i1];

            for (iarrays = 0; iarrays < narrays; ++iarrays) {
                // 检查当前轴上数组的形状是否不是1,如果都不是1,则可能需要交换
                if (PyArray_SHAPE(arrays[iarrays])[ax_j0] != 1 &&
                            PyArray_SHAPE(arrays[iarrays])[ax_j1] != 1) {
                    // 比较当前两个步长的绝对值大小,决定是否需要交换
                    if (s_intp_abs(PyArray_STRIDES(arrays[iarrays])[ax_j0]) <=
                            s_intp_abs(PyArray_STRIDES(arrays[iarrays])[ax_j1])) {
                        /*
                         * 即使还不是明确的歧义情况,也设置为需要交换,
                         * 因为在不同操作数之间的冲突情况下,C顺序优先。
                         */
                        shouldswap = 0;
                    }
                    else {
                        /* 只有在仍然存在歧义时才设置为需要交换 */
                        if (ambig) {
                            shouldswap = 1;
                        }
                    }

                    /*
                     * 已经进行了比较,因此不再是歧义的
                     */
                    ambig = 0;
                }
            }
            /*
             * 如果比较是明确的,要么将 'ipos' 移动到 'i1',要么停止寻找插入点
             */
            if (!ambig) {
                if (shouldswap) {
                    ipos = i1;
                }
                else {
                    break;
                }
            }
        }

        /* 将 out_strideperm[i0] 插入到正确的位置 */
        if (ipos != i0) {
            for (i1 = i0; i1 > ipos; --i1) {
                out_strideperm[i1] = out_strideperm[i1-1];
            }
            out_strideperm[ipos] = ax_j0;
        }
    }
/*NUMPY_API
 * Ravel
 * Returns a contiguous array
 */
NPY_NO_EXPORT PyObject *
PyArray_Ravel(PyArrayObject *arr, NPY_ORDER order)
{
    // 新维度结构体,用于重塑数组形状
    PyArray_Dims newdim = {NULL,1};
    // 初始的尺寸值为-1,用于自动计算新形状
    npy_intp val[1] = {-1};

    newdim.ptr = val;

    // 如果指定保持原始顺序
    if (order == NPY_KEEPORDER) {
        /* This handles some corner cases, such as 0-d arrays as well */
        // 处理一些特殊情况,比如0维数组
        if (PyArray_IS_C_CONTIGUOUS(arr)) {
            order = NPY_CORDER; // 如果是C连续的,使用C顺序
        }
        else if (PyArray_IS_F_CONTIGUOUS(arr)) {
            order = NPY_FORTRANORDER; // 如果是Fortran连续的,使用Fortran顺序
        }
    }
    // 如果指定任意顺序
    else if (order == NPY_ANYORDER) {
        // 根据数组是否Fortran连续决定顺序
        order = PyArray_ISFORTRAN(arr) ? NPY_FORTRANORDER : NPY_CORDER;
    }

    // 如果顺序是C顺序且数组是C连续的
    if (order == NPY_CORDER && PyArray_IS_C_CONTIGUOUS(arr)) {
        // 返回一个新的数组,按指定的C顺序重塑
        return PyArray_Newshape(arr, &newdim, NPY_CORDER);
    }
    // 如果顺序是Fortran顺序且数组是Fortran连续的
    else if (order == NPY_FORTRANORDER && PyArray_IS_F_CONTIGUOUS(arr)) {
        // 返回一个新的数组,按指定的Fortran顺序重塑
        return PyArray_Newshape(arr, &newdim, NPY_FORTRANORDER);
    }
    /* For KEEPORDER, check if we can make a flattened view */
    // 对于保持原始顺序,检查是否可以创建扁平视图
    else if (order == NPY_KEEPORDER) {
        // 创建排序后的步幅列表
        npy_stride_sort_item strideperm[NPY_MAXDIMS];
        npy_intp stride;
        int i, ndim = PyArray_NDIM(arr);

        // 创建按步幅排序的排列
        PyArray_CreateSortedStridePerm(PyArray_NDIM(arr),
                                PyArray_STRIDES(arr), strideperm);

        // 输出数组必须是连续的,因此第一个步幅是固定的
        stride = PyArray_ITEMSIZE(arr);

        // 从最后一个维度开始检查
        for (i = ndim-1; i >= 0; --i) {
            // 大小为1的维度不重要
            if (PyArray_DIM(arr, strideperm[i].perm) == 1) {
                continue;
            }
            // 如果步幅不匹配,中断循环
            if (strideperm[i].stride != stride) {
                break;
            }
            // 更新步幅
            stride *= PyArray_DIM(arr, strideperm[i].perm);
        }

        // 如果所有步幅匹配连续布局,则返回视图
        if (i < 0) {
            stride = PyArray_ITEMSIZE(arr);
            val[0] = PyArray_SIZE(arr);

            // 增加数组的引用计数并返回新数组
            Py_INCREF(PyArray_DESCR(arr));
            return PyArray_NewFromDescrAndBase(
                    Py_TYPE(arr), PyArray_DESCR(arr),
                    1, val, &stride, PyArray_BYTES(arr),
                    PyArray_FLAGS(arr), (PyObject *)arr, (PyObject *)arr);
        }
    }

    // 否则,返回数组的扁平视图
    return PyArray_Flatten(arr, order);
}
    }
    // 将 ret 转换为 PyObject 指针并返回
    return (PyObject *)ret;
/*NUMPY_API
 *
 * Removes the axes flagged as True from the array,
 * modifying it in place. If an axis flagged for removal
 * has a shape entry bigger than one, this effectively selects
 * index zero for that axis.
 *
 * WARNING: If an axis flagged for removal has a shape equal to zero,
 *          the array will point to invalid memory. The caller must
 *          validate this!
 *          If an axis flagged for removal has a shape larger than one,
 *          the aligned flag (and in the future the contiguous flags),
 *          may need explicit update.
 *
 * For example, this can be used to remove the reduction axes
 * from a reduction result once its computation is complete.
 */
NPY_NO_EXPORT void
PyArray_RemoveAxesInPlace(PyArrayObject *arr, const npy_bool *flags)
{
    // 转换数组对象的字段到具体类型
    PyArrayObject_fields *fa = (PyArrayObject_fields *)arr;
    // 获取数组的维度和步长信息
    npy_intp *shape = fa->dimensions, *strides = fa->strides;
    int idim, ndim = fa->nd, idim_out = 0;

    /* Compress the dimensions and strides */
    // 压缩维度和步长信息
    for (idim = 0; idim < ndim; ++idim) {
        // 如果标志为真,则跳过该维度
        if (!flags[idim]) {
            // 将非跳过的维度信息复制到输出的维度和步长数组中
            shape[idim_out] = shape[idim];
            strides[idim_out] = strides[idim];
            // 更新输出维度索引
            ++idim_out;
        }
    }

    /* The final number of dimensions */
    // 更新数组对象的维度数
    fa->nd = idim_out;

    /* NOTE: This is only necessary if a dimension with size != 1 was removed */
    // 如果移除了大小不为1的维度,则需要更新连续性标志
    PyArray_UpdateFlags(arr, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_F_CONTIGUOUS);
}

.\numpy\numpy\_core\src\multiarray\shape.h

#ifndef NUMPY_CORE_SRC_MULTIARRAY_SHAPE_H_
#define NUMPY_CORE_SRC_MULTIARRAY_SHAPE_H_

#include "conversion_utils.h"

/*
 * 创建一个按照 NpyIter 对象的 KEEPORDER 行为进行排序的步幅排列。
 * 因为这是基于多个输入步幅进行操作,np.ndarray 结构体 npy_stride_sort_item 的 'stride' 成员无用,
 * 我们简单地对索引列表进行 argsort。
 *
 * 调用者应该已经验证每个数组在数组列表中的 'ndim' 是否匹配。
 */
NPY_NO_EXPORT void
PyArray_CreateMultiSortedStridePerm(int narrays, PyArrayObject **arrays,
                        int ndim, int *out_strideperm);

/*
 * 类似于 PyArray_Squeeze,但允许调用者选择要挤压的大小为一的维度的子集。
 */
NPY_NO_EXPORT PyObject *
PyArray_SqueezeSelected(PyArrayObject *self, npy_bool *axis_flags);

/*
 * 返回矩阵的转置(交换最后两个维度)。
 */
NPY_NO_EXPORT PyObject *
PyArray_MatrixTranspose(PyArrayObject *ap);

/*
 * 使用复制模式参数 _copy 进行数组重塑。
 */
NPY_NO_EXPORT PyObject *
_reshape_with_copy_arg(PyArrayObject *array, PyArray_Dims *newdims,
                       NPY_ORDER order, NPY_COPYMODE copy);

#endif  /* NUMPY_CORE_SRC_MULTIARRAY_SHAPE_H_ */


这些注释解释了每个函数的目的和关键参数。每个注释都遵循了代码本身的结构和逻辑顺序。

.\numpy\numpy\_core\src\multiarray\strfuncs.c

/*
 * 定义以避免使用已弃用的 NumPy API 版本
 */
#define NPY_NO_DEPRECATED_API NPY_API_VERSION

/*
 * 定义用于多维数组模块的标志
 */
#define _MULTIARRAYMODULE

/*
 * 清除 PY_SSIZE_T_CLEAN 宏定义,确保在包含 Python.h 之前不会定义 ssize_t
 */
#define PY_SSIZE_T_CLEAN

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

/*
 * 包含 NumPy 提供的数组对象头文件
 */
#include "numpy/arrayobject.h"

/*
 * 包含 NumPy 兼容性模块的头文件
 */
#include "npy_pycompat.h"

/*
 * 包含 NumPy 导入模块的头文件
 */
#include "npy_import.h"

/*
 * 包含多维数组模块的头文件
 */
#include "multiarraymodule.h"

/*
 * 包含字符串处理函数的头文件
 */
#include "strfuncs.h"

/*
 * 定义一个静态函数 npy_PyErr_SetStringChained,设置一个字符串类型的异常,并链式传递之前的异常
 */
static void
npy_PyErr_SetStringChained(PyObject *type, const char *message)
{
    PyObject *exc, *val, *tb;

    /*
     * 获取当前的异常信息
     */
    PyErr_Fetch(&exc, &val, &tb);
    
    /*
     * 设置一个新的异常信息
     */
    PyErr_SetString(type, message);
    
    /*
     * 将之前捕获的异常信息链式传递
     */
    npy_PyErr_ChainExceptionsCause(exc, val, tb);
}

/*
 * NUMPY_API
 * 将数组打印函数设置为 Python 函数。
 * 该函数不会导出给外部模块使用。
 */
NPY_NO_EXPORT void
PyArray_SetStringFunction(PyObject *op, int repr)
{
    /*
     * 抛出 ValueError 异常,因为 PyArray_SetStringFunction 已被移除
     */
    PyErr_SetString(PyExc_ValueError, "PyArray_SetStringFunction was removed");
}

/*
 * NUMPY_API
 * 返回一个数组对象的字符串表示形式。
 * 该函数不会导出给外部模块使用。
 */
NPY_NO_EXPORT PyObject *
array_repr(PyArrayObject *self)
{
    /*
     * 延迟导入 numpy._core.arrayprint 模块中的 _default_array_repr 函数,
     * 避免在模块加载时引起循环导入问题。
     */
    npy_cache_import("numpy._core.arrayprint", "_default_array_repr",
                     &npy_thread_unsafe_state._default_array_repr);
    if (npy_thread_unsafe_state._default_array_repr == NULL) {
        /*
         * 如果无法配置默认的 ndarray.__repr__ 函数,则抛出 RuntimeError 异常
         */
        npy_PyErr_SetStringChained(PyExc_RuntimeError,
                "Unable to configure default ndarray.__repr__");
        return NULL;
    }
    return PyObject_CallFunctionObjArgs(
            npy_thread_unsafe_state._default_array_repr, self, NULL);
}

/*
 * NUMPY_API
 * 返回一个数组对象的字符串表示形式。
 * 该函数不会导出给外部模块使用。
 */
NPY_NO_EXPORT PyObject *
array_str(PyArrayObject *self)
{
    /*
     * 延迟导入 numpy._core.arrayprint 模块中的 _default_array_str 函数,
     * 避免在模块加载时引起循环导入问题。
     */
    npy_cache_import("numpy._core.arrayprint", "_default_array_str",
                     &npy_thread_unsafe_state._default_array_str);
    if (npy_thread_unsafe_state._default_array_str == NULL) {
        /*
         * 如果无法配置默认的 ndarray.__str__ 函数,则抛出 RuntimeError 异常
         */
        npy_PyErr_SetStringChained(PyExc_RuntimeError,
                "Unable to configure default ndarray.__str__");
        return NULL;
    }
    return PyObject_CallFunctionObjArgs(
            npy_thread_unsafe_state._default_array_str, self, NULL);
}

/*
 * NUMPY_API
 * 格式化数组对象。
 * 该函数不会导出给外部模块使用。
 */
NPY_NO_EXPORT PyObject *
array_format(PyArrayObject *self, PyObject *args)
{
    PyObject *format;
    if (!PyArg_ParseTuple(args, "O:__format__", &format))
        return NULL;

    /* 
     * 对于 0 维数组,转发到标量类型
     */
    if (PyArray_NDIM(self) == 0) {
        PyObject *item = PyArray_ToScalar(PyArray_DATA(self), self);
        PyObject *res;

        if (item == NULL) {
            return NULL;
        }
        res = PyObject_Format(item, format);
        Py_DECREF(item);
        return res;
    }
    /* 
     * 其他情况下使用内置方法
     */
    else {
        return PyObject_CallMethod(
            (PyObject *)&PyBaseObject_Type, "__format__", "OO",
            (PyObject *)self, format
        );
    }
}

.\numpy\numpy\_core\src\multiarray\strfuncs.h

#ifndef NUMPY_CORE_SRC_MULTIARRAY_STRFUNCS_H_
#define NUMPY_CORE_SRC_MULTIARRAY_STRFUNCS_H_

// 声明一个不导出的函数,用于设置对象的字符串表示函数
NPY_NO_EXPORT void
PyArray_SetStringFunction(PyObject *op, int repr);

// 声明一个不导出的函数,用于返回数组对象的字符串表示形式
NPY_NO_EXPORT PyObject *
array_repr(PyArrayObject *self);

// 声明一个不导出的函数,用于返回数组对象的字符串表示形式
NPY_NO_EXPORT PyObject *
array_str(PyArrayObject *self);

// 声明一个不导出的函数,用于根据指定格式返回数组对象的字符串表示形式
NPY_NO_EXPORT PyObject *
array_format(PyArrayObject *self, PyObject *args);

#endif  /* NUMPY_CORE_SRC_MULTIARRAY_STRFUNCS_H_ */

.\numpy\numpy\_core\src\multiarray\stringdtype\casts.c

/*
定义了一个宏函数 ANY_TO_STRING_RESOLVE_DESCRIPTORS,用于处理类型转换描述符的解析和处理。
此宏函数展开后,会生成一个静态函数 any_to_string_SAFE_resolve_descriptors 和一个静态函数 any_to_string_SAME_KIND_resolve_descriptors。

any_to_string_SAFE_resolve_descriptors 函数:
    参数:
        - PyObject *NPY_UNUSED(self): 指向 Python 对象的指针,未使用,表示不使用该参数。
        - PyArray_DTypeMeta *NPY_UNUSED(dtypes[2]): 指向包含数据类型元信息的数组的指针,未使用,表示不使用该参数。
        - PyArray_Descr *given_descrs[2]: 包含两个指向数组数据类型描述符的指针的数组。
        - PyArray_Descr *loop_descrs[2]: 用于存储处理后的数据类型描述符的数组。
        - npy_intp *NPY_UNUSED(view_offset): 指向整数数组的指针,未使用,表示不使用该参数。
    函数逻辑:
        - 检查给定的第二个描述符 given_descrs[1] 是否为 NULL。
        - 如果 given_descrs[1] 为 NULL,则创建一个新的字符串数据类型描述符 new,并将其存储在 loop_descrs[1] 中。
        - 如果 given_descrs[1] 不为 NULL,则增加其引用计数,并将其存储在 loop_descrs[1] 中。
        - 增加给定的第一个描述符 given_descrs[0] 的引用计数,并将其存储在 loop_descrs[0] 中。
        - 返回 NPY_SAFE_CASTING。

any_to_string_SAME_KIND_resolve_descriptors 函数:
    参数和逻辑与 any_to_string_SAFE_resolve_descriptors 函数类似,区别在于最后返回的是 NPY_SAME_KIND_CASTING。

static NPY_CASTING
string_to_string_resolve_descriptors(PyObject *NPY_UNUSED(self),
                                     PyArray_DTypeMeta *NPY_UNUSED(dtypes[2]),
                                     PyArray_Descr *given_descrs[2],
                                     PyArray_Descr *loop_descrs[2],
                                     npy_intp *view_offset)
{
*/

/*
上述代码段中的注释主要是解释了宏定义 ANY_TO_STRING_RESOLVE_DESCRIPTORS 的作用和展开后的两个静态函数 any_to_string_SAFE_resolve_descriptors 和 any_to_string_SAME_KIND_resolve_descriptors 的参数及逻辑。
*/
    # 检查给定描述符列表中的第二个描述符是否为 NULL
    if (given_descrs[1] == NULL) {
        # 如果第二个描述符为 NULL,则使用第一个描述符创建一个新的字符串类型描述符
        loop_descrs[1] = stringdtype_finalize_descr(given_descrs[0]);
    }
    else {
        # 如果第二个描述符不为 NULL,则增加其引用计数,并直接使用该描述符
        Py_INCREF(given_descrs[1]);
        loop_descrs[1] = given_descrs[1];
    }

    # 增加第一个描述符的引用计数,并直接使用该描述符
    Py_INCREF(given_descrs[0]);
    loop_descrs[0] = given_descrs[0];

    # 将循环中使用的第一个和第二个描述符分别转换为字符串类型描述符对象
    PyArray_StringDTypeObject *descr0 = (PyArray_StringDTypeObject *)loop_descrs[0];
    PyArray_StringDTypeObject *descr1 = (PyArray_StringDTypeObject *)loop_descrs[1];

    # 如果第一个描述符有 NA 对象而第二个描述符没有,则转换是不安全的
    if ((descr0->na_object != NULL) && (descr1->na_object == NULL)) {
        // 从带有 NA 的 dtype 转换到没有 NA 的 dtype 是不安全的,因为会丢失信息
        // 从没有 NA 的 dtype 转换到带有 NA 的 dtype 是安全的,因为源数据没有 NA 可能丢失
        return NPY_UNSAFE_CASTING;
    }

    # 视图(view)仅在共享分配器(allocator)的描述符之间合法(例如同一对象)
    if (descr0->allocator == descr1->allocator) {
        // 如果描述符共享相同的分配器,则视图偏移量设置为 0
        *view_offset = 0;
    };

    # 默认情况下,允许无需类型转换的赋值(casting)
    return NPY_NO_CASTING;
}

static int
string_to_string(PyArrayMethod_Context *context, char *const data[],
                 npy_intp const dimensions[], npy_intp const strides[],
                 NpyAuxData *NPY_UNUSED(auxdata))
{
    // 获取输入和输出的字符串描述符
    PyArray_StringDTypeObject *idescr = (PyArray_StringDTypeObject *)context->descriptors[0];
    PyArray_StringDTypeObject *odescr = (PyArray_StringDTypeObject *)context->descriptors[1];
    // 检查输入和输出是否包含空值
    int in_has_null = idescr->na_object != NULL;
    int out_has_null = odescr->na_object != NULL;
    // 获取输入的空值名称
    const npy_static_string *in_na_name = &idescr->na_name;
    // 获取数据的维度
    npy_intp N = dimensions[0];
    // 获取输入和输出数据指针
    char *in = data[0];
    char *out = data[1];
    // 获取输入和输出的步长
    npy_intp in_stride = strides[0];
    npy_intp out_stride = strides[1];

    // 分配输入和输出的字符串分配器
    npy_string_allocator *allocators[2] = {NULL, NULL};
    NpyString_acquire_allocators(2, context->descriptors, allocators);
    npy_string_allocator *iallocator = allocators[0];
    npy_string_allocator *oallocator = allocators[1];


    while (N--) {
        // 读取输入字符串
        const npy_packed_static_string *s = (npy_packed_static_string *)in;
        // 获取输出字符串
        npy_packed_static_string *os = (npy_packed_static_string *)out;
        // 如果输入和输出不共享内存
        if (!NpyString_share_memory(s, iallocator, os, oallocator)) {
            // 如果输入包含空值但输出不包含,并且输入字符串是空值
            if (in_has_null && !out_has_null && NpyString_isnull(s)) {
                // 执行不安全的转换,将空值包装为输出字符串
                if (NpyString_pack(oallocator, os, in_na_name->buf,
                                   in_na_name->size) < 0) {
                    // 内存错误处理
                    npy_gil_error(PyExc_MemoryError,
                              "Failed to pack string in string to string "
                              "cast.");
                    goto fail;
                }
            }
            // 否则,执行自由和复制操作
            else if (free_and_copy(iallocator, oallocator, s, os,
                                   "string to string cast") < 0) {
                goto fail;
            }
        }

        // 更新输入和输出指针位置
        in += in_stride;
        out += out_stride;
    }

    // 释放字符串分配器
    NpyString_release_allocators(2, allocators);

    return 0;

fail:

    // 失败时释放字符串分配器并返回错误码
    NpyString_release_allocators(2, allocators);

    return -1;
}

static PyType_Slot s2s_slots[] = {
        // 解析描述符方法槽
        {NPY_METH_resolve_descriptors, &string_to_string_resolve_descriptors},
        // 字符串到字符串的循环处理方法槽
        {NPY_METH_strided_loop, &string_to_string},
        // 不对齐的字符串到字符串循环处理方法槽
        {NPY_METH_unaligned_strided_loop, &string_to_string},
        // 终止槽
        {0, NULL}};

static char *s2s_name = "cast_StringDType_to_StringDType";

// unicode to string

static int
unicode_to_string(PyArrayMethod_Context *context, char *const data[],
                  npy_intp const dimensions[], npy_intp const strides[],
                  NpyAuxData *NPY_UNUSED(auxdata))
{
    // 获取描述符数组
    PyArray_Descr *const *descrs = context->descriptors;
    // 获取输出描述符
    PyArray_StringDTypeObject *sdescr = (PyArray_StringDTypeObject *)descrs[1];

    // 获取输出字符串的分配器
    npy_string_allocator *allocator = NpyString_acquire_allocator(sdescr);

    // 计算最大输入大小
    long max_in_size = (descrs[0]->elsize) / sizeof(Py_UCS4);

    // 获取数据的维度
    npy_intp N = dimensions[0];
    // 获取输入和输出数据指针
    Py_UCS4 *in = (Py_UCS4 *)data[0];
    char *out = data[1];
    # 计算输入数组的第一个维度步长,除以每个元素的字节数得到 UCS4 编码的步长
    npy_intp in_stride = strides[0] / sizeof(Py_UCS4);
    # 输出数组的步长,即每个元素之间的间隔
    npy_intp out_stride = strides[1];

    # 循环处理每个元素
    while (N--) {
        # 初始化输出字节数和代码点数
        size_t out_num_bytes = 0;
        size_t num_codepoints = 0;
        
        # 检查输入的 UTF-8 字符串,获取其中的代码点数和输出的字节数
        if (utf8_size(in, max_in_size, &num_codepoints, &out_num_bytes) ==
            -1) {
            # 如果出现无效的 Unicode 代码点,抛出类型错误并跳转到处理失败的标签
            npy_gil_error(PyExc_TypeError, "Invalid unicode code point found");
            goto fail;
        }
        
        # 用于存储输出字符串的静态字符串结构体
        npy_static_string out_ss = {0, NULL};
        
        # 加载新的字符串到静态字符串结构体中,进行 Unicode 到字符串的转换
        if (load_new_string((npy_packed_static_string *)out,
                            &out_ss, out_num_bytes, allocator,
                            "unicode to string cast") == -1) {
            # 如果加载字符串失败,跳转到处理失败的标签
            goto fail;
        }
        
        // 忽略常量以填充缓冲区

        # 将输出缓冲区转换为字符指针
        char *out_buf = (char *)out_ss.buf;
        
        # 遍历每个代码点
        for (size_t i = 0; i < num_codepoints; i++) {
            # 获取当前代码点
            Py_UCS4 code = in[i];

            # 用于存储 UTF-8 字节的数组
            char utf8_c[4] = {0};

            # 将 UCS4 编码的代码点转换为 UTF-8 字符串
            size_t num_bytes = ucs4_code_to_utf8_char(code, utf8_c);

            # 将 UTF-8 字符串复制到输出缓冲区
            strncpy(out_buf, utf8_c, num_bytes);

            # 更新输出缓冲区指针,移动到下一个字符的位置
            out_buf += num_bytes;
        }

        # 将输出缓冲区指针重置到字符串的起始位置
        out_buf -= out_num_bytes;

        # 更新输入和输出数组指针,以处理下一个元素
        in += in_stride;
        out += out_stride;
    }

    # 释放分配器使用的内存资源
    NpyString_release_allocator(allocator);

    # 返回成功标志
    return 0;
// 释放 NpyString 分配的内存空间的分配器
NpyString_release_allocator(allocator);

// 返回 -1,表示函数执行失败
return -1;
}

// 定义 PyType_Slot 数组,包含解析描述符和相应的函数指针
static PyType_Slot u2s_slots[] = {{NPY_METH_resolve_descriptors,
                                   &any_to_string_SAME_KIND_resolve_descriptors},
                                  {NPY_METH_strided_loop, &unicode_to_string},
                                  {0, NULL}};

// 定义字符串 u2s_name,用于类型转换从 Unicode 到 StringDType
static char *u2s_name = "cast_Unicode_to_StringDType";

// 将字符串转换为固定宽度数据类型时的解析描述符处理函数
static NPY_CASTING
string_to_fixed_width_resolve_descriptors(
        PyObject *NPY_UNUSED(self),
        PyArray_DTypeMeta *NPY_UNUSED(dtypes[2]),
        PyArray_Descr *given_descrs[2],
        PyArray_Descr *loop_descrs[2],
        npy_intp *NPY_UNUSED(view_offset))
{
    if (given_descrs[1] == NULL) {
        // 如果给定描述符为 NULL,则设置类型错误并返回 -1
        // 表示当前不支持从 StringDType 到固定宽度数据类型的转换
        PyErr_SetString(
                PyExc_TypeError,
                "Casting from StringDType to a fixed-width dtype with an "
                "unspecified size is not currently supported, specify "
                "an explicit size for the output dtype instead.");
        return (NPY_CASTING)-1;
    }
    else {
        // 增加给定描述符的引用计数,并设置循环描述符
        Py_INCREF(given_descrs[1]);
        loop_descrs[1] = given_descrs[1];
    }

    // 增加给定描述符的引用计数,并设置循环描述符
    Py_INCREF(given_descrs[0]);
    loop_descrs[0] = given_descrs[0];

    // 返回相同类型的类型转换标志
    return NPY_SAME_KIND_CASTING;
}

// 加载可空字符串的函数,从静态字符串中加载到动态分配的字符串中
static int
load_nullable_string(const npy_packed_static_string *ps,
                     npy_static_string *s,
                     int has_null,
                     int has_string_na,
                     const npy_static_string *default_string,
                     const npy_static_string *na_name,
                     npy_string_allocator *allocator,
                     char *context)
{
    // 使用 NpyString_load 函数加载字符串,如果加载失败则报错并返回 -1
    int is_null = NpyString_load(allocator, ps, s);
    if (is_null == -1) {
        npy_gil_error(PyExc_MemoryError,
                      "Failed to load string in %s", context);
        return -1;
    }
    else if (is_null) {
        if (has_null && !has_string_na) {
            // 如果字符串为 NULL,且支持 NULL,但没有设置字符串 NA,则使用 NA 名称
            // 否则使用默认字符串
            *s = *na_name;
        }
        else {
            *s = *default_string;
        }
    }
    return 0;
}

// 字符串到 Unicode 的转换函数,处理 PyArrayMethod_Context 上下文和数据
static int
string_to_unicode(PyArrayMethod_Context *context, char *const data[],
                  npy_intp const dimensions[], npy_intp const strides[],
                  NpyAuxData *NPY_UNUSED(auxdata))
{
    // 获取字符串类型的描述符
    PyArray_StringDTypeObject *descr = (PyArray_StringDTypeObject *)context->descriptors[0];
    // 获取字符串分配器
    npy_string_allocator *allocator = NpyString_acquire_allocator(descr);
    // 检查是否有 NULL 值对象
    int has_null = descr->na_object != NULL;
    // 检查是否有字符串 NA
    int has_string_na = descr->has_string_na;
    // 默认字符串
    const npy_static_string *default_string = &descr->default_string;
    // NA 名称
    const npy_static_string *na_name = &descr->na_name;
    // 获取数据的维度大小
    npy_intp N = dimensions[0];
    // 输入数据的指针
    char *in = data[0];
    // 输出数据的指针
    Py_UCS4 *out = (Py_UCS4 *)data[1];
    // 输入数据的步长
    npy_intp in_stride = strides[0];
    // 输出数据的步长,转换为 Py_UCS4 的大小
    npy_intp out_stride = strides[1] / sizeof(Py_UCS4);
    // 计算每个输出的最大 UCS4 字符数
    size_t max_out_size = (context->descriptors[1]->elsize) / sizeof(Py_UCS4);

    // 循环处理输入数据,N 表示迭代次数
    while (N--) {
        // 从输入中读取一个静态字符串结构体 ps
        const npy_packed_static_string *ps = (npy_packed_static_string *)in;
        // 初始化一个静态字符串结构体 s
        npy_static_string s = {0, NULL};
        
        // 加载可空字符串,转换为 Unicode 字符串 s
        if (load_nullable_string(ps, &s, has_null, has_string_na,
                                 default_string, na_name, allocator,
                                 "in string to unicode cast") == -1) {
            // 如果加载失败,跳转到失败处理标签
            goto fail;
        }

        // 转换为无符号字符指针
        unsigned char *this_string = (unsigned char *)(s.buf);
        // 字符串字节数
        size_t n_bytes = s.size;
        // 总字节数
        size_t tot_n_bytes = 0;

        // 如果字符串长度为0,填充输出数组为0
        if (n_bytes == 0) {
            for (int i=0; i < max_out_size; i++) {
                out[i] = (Py_UCS4)0;
            }
        }
        else {
            int i = 0;
            // 将 UTF-8 字符转换为 UCS4 编码,填充输出数组直到达到最大输出长度或者处理完所有字节
            for (; i < max_out_size && tot_n_bytes < n_bytes; i++) {
                int num_bytes = utf8_char_to_ucs4_code(this_string, &out[i]);

                // 移动到下一个字符
                this_string += num_bytes;
                tot_n_bytes += num_bytes;
            }
            // 如果未填充满最大输出长度,剩余部分填充为0
            for(; i < max_out_size; i++) {
                out[i] = (Py_UCS4)0;
            }
        }

        // 更新输入和输出指针,以及释放分配器资源
        in += in_stride;
        out += out_stride;
    }

    // 释放分配器资源
    NpyString_release_allocator(allocator);

    // 返回成功状态
    return 0;
// 释放分配的内存,并返回失败代码
fail:
    NpyString_release_allocator(allocator);
    return -1;
}

// 定义一个静态的 PyType_Slot 数组,包含解析描述符和字符串到Unicode的函数指针
static PyType_Slot s2u_slots[] = {
        {NPY_METH_resolve_descriptors, &string_to_fixed_width_resolve_descriptors},
        {NPY_METH_strided_loop, &string_to_unicode},
        {0, NULL}};

// 定义一个静态的字符串,用于表示函数名称
static char *s2u_name = "cast_StringDType_to_Unicode";

// string to bool

// 解析描述符的函数,将字符串转换为布尔值
static NPY_CASTING
string_to_bool_resolve_descriptors(PyObject *NPY_UNUSED(self),
                                   PyArray_DTypeMeta *NPY_UNUSED(dtypes[2]),
                                   PyArray_Descr *given_descrs[2],
                                   PyArray_Descr *loop_descrs[2],
                                   npy_intp *NPY_UNUSED(view_offset))
{
    // 如果给定的第二个描述符为空,则使用 NPY_BOOL 类型创建一个新的描述符
    if (given_descrs[1] == NULL) {
        loop_descrs[1] = PyArray_DescrNewFromType(NPY_BOOL);
    }
    else {
        // 否则增加给定描述符的引用计数并使用它
        Py_INCREF(given_descrs[1]);
        loop_descrs[1] = given_descrs[1];
    }

    // 增加给定描述符的引用计数并使用它
    Py_INCREF(given_descrs[0]);
    loop_descrs[0] = given_descrs[0];

    // 返回不安全的强制转换类型
    return NPY_UNSAFE_CASTING;
}

// 将字符串转换为布尔值的函数
static int
string_to_bool(PyArrayMethod_Context *context, char *const data[],
               npy_intp const dimensions[], npy_intp const strides[],
               NpyAuxData *NPY_UNUSED(auxdata))
{
    // 获取描述符对象
    PyArray_StringDTypeObject *descr = (PyArray_StringDTypeObject *)context->descriptors[0];
    // 获取字符串分配器
    npy_string_allocator *allocator = NpyString_acquire_allocator(descr);
    // 检查是否有 NULL 对象
    int has_null = descr->na_object != NULL;
    // 检查是否有字符串 NA
    int has_string_na = descr->has_string_na;
    // 检查是否有 NaN NA
    int has_nan_na = descr->has_nan_na;
    // 获取默认字符串
    const npy_static_string *default_string = &descr->default_string;

    // 获取数据维度
    npy_intp N = dimensions[0];
    // 输入数据指针
    char *in = data[0];
    // 输出数据指针
    char *out = data[1];

    // 输入数据步长
    npy_intp in_stride = strides[0];
    // 输出数据步长
    npy_intp out_stride = strides[1];

    // 遍历数据进行转换
    while (N--) {
        // 获取紧凑静态字符串对象
        const npy_packed_static_string *ps = (npy_packed_static_string *)in;
        // 初始化静态字符串对象
        npy_static_string s = {0, NULL};
        // 加载字符串到静态字符串对象中
        int is_null = NpyString_load(allocator, ps, &s);
        // 如果加载失败则报错并跳转到失败标签
        if (is_null == -1) {
            npy_gil_error(PyExc_MemoryError, "Failed to load string in string to bool cast");
            goto fail;
        }
        // 如果字符串为空
        else if (is_null) {
            // 如果存在 NULL 对象且不存在字符串 NA
            if (has_null && !has_string_na) {
                // 如果存在 NaN NA,则将其视为真值,按照 Python 的规则
                if (has_nan_na) {
                    *out = NPY_TRUE;
                }
                // 否则将其视为假值
                else {
                    *out = NPY_FALSE;
                }
            }
            // 如果不存在 NULL 对象,则将默认字符串的大小作为条件进行判断
            else {
                *out = (npy_bool)(default_string->size == 0);
            }
        }
        // 如果字符串长度为零,则将输出设置为假值
        else if (s.size == 0) {
            *out = NPY_FALSE;
        }
        // 否则将输出设置为真值
        else {
            *out = NPY_TRUE;
        }

        // 更新输入和输出指针
        in += in_stride;
        out += out_stride;
    }

    // 释放字符串分配器
    NpyString_release_allocator(allocator);

    return 0;

// 失败时释放字符串分配器并返回失败代码
fail:
    NpyString_release_allocator(allocator);
    return -1;
}
// 定义 PyType_Slot 结构体数组 s2b_slots,用于描述字符串到布尔类型转换的方法
static PyType_Slot s2b_slots[] = {
    // 解析描述符方法,使用 string_to_bool_resolve_descriptors 函数
    {NPY_METH_resolve_descriptors, &string_to_bool_resolve_descriptors},
    // 使用 string_to_bool 函数进行跨步循环方法
    {NPY_METH_strided_loop, &string_to_bool},
    // 数组结束标记
    {0, NULL}
};

// 字符串 "cast_StringDType_to_Bool",用于标识字符串到布尔类型转换
static char *s2b_name = "cast_StringDType_to_Bool";

// 布尔到字符串的转换

// 定义 bool_to_string 函数,将布尔值转换为字符串
static int
bool_to_string(PyArrayMethod_Context *context, char *const data[],
               npy_intp const dimensions[], npy_intp const strides[],
               NpyAuxData *NPY_UNUSED(auxdata))
{
    // 获取数组维度大小
    npy_intp N = dimensions[0];
    // 输入数据指针
    char *in = data[0];
    // 输出数据指针
    char *out = data[1];

    // 输入和输出的步长
    npy_intp in_stride = strides[0];
    npy_intp out_stride = strides[1];

    // 获取描述符对象
    PyArray_StringDTypeObject *descr = (PyArray_StringDTypeObject *)context->descriptors[1];
    // 获取字符串分配器
    npy_string_allocator *allocator = NpyString_acquire_allocator(descr);

    // 循环处理每个元素
    while (N--) {
        // 输出数据转换为静态字符串指针
        npy_packed_static_string *out_pss = (npy_packed_static_string *)out;
        // 返回值字符串指针初始化为空
        char *ret_val = NULL;
        // 返回值字符串大小初始化为0
        size_t size = 0;
        
        // 根据布尔值设置返回值和大小
        if ((npy_bool)(*in) == NPY_TRUE) {
            ret_val = "True";
            size = 4;
        }
        else if ((npy_bool)(*in) == NPY_FALSE) {
            ret_val = "False";
            size = 5;
        }
        else {
            // 如果布尔值无效,则引发运行时错误
            npy_gil_error(PyExc_RuntimeError,
                          "invalid value encountered in bool to string cast");
            // 转到错误处理标签
            goto fail;
        }
        
        // 尝试将返回值打包到输出静态字符串指针中
        if (NpyString_pack(allocator, out_pss, ret_val, size) < 0) {
            // 如果打包失败,则引发内存错误
            npy_gil_error(PyExc_MemoryError,
                          "Failed to pack string in bool to string cast");
            // 转到错误处理标签
            goto fail;
        }
        
        // 更新输入和输出指针位置
        in += in_stride;
        out += out_stride;
    }

    // 释放字符串分配器
    NpyString_release_allocator(allocator);

    // 返回成功状态
    return 0;

fail:
    // 失败时释放字符串分配器
    NpyString_release_allocator(allocator);

    // 返回失败状态
    return -1;
}

// 定义 PyType_Slot 结构体数组 b2s_slots,用于描述布尔到字符串类型转换的方法
static PyType_Slot b2s_slots[] = {
    // 解析描述符方法,使用 any_to_string_SAFE_resolve_descriptors 函数
    {NPY_METH_resolve_descriptors, &any_to_string_SAFE_resolve_descriptors},
    // 使用 bool_to_string 函数进行跨步循环方法
    {NPY_METH_strided_loop, &bool_to_string},
    // 数组结束标记
    {0, NULL}
};

// 字符串 "cast_Bool_to_StringDType",用于标识布尔到字符串类型转换
static char *b2s_name = "cast_Bool_to_StringDType";

// 字符串和 (u)int 数据类型之间的转换

// 定义 load_non_nullable_string 函数,加载非空字符串并进行类型转换
static int
load_non_nullable_string(char *in, int has_null, const npy_static_string *default_string,
                         npy_static_string *string_to_load, npy_string_allocator *allocator,
                         int has_gil)
{
    // 输入静态字符串指针转换为打包的静态字符串指针
    const npy_packed_static_string *ps = (npy_packed_static_string *)in;
    // 加载静态字符串并返回是否为空
    int isnull = NpyString_load(allocator, ps, string_to_load);
    
    // 如果加载失败
    if (isnull == -1) {
        // 错误消息
        char *msg = "Failed to load string for conversion to a non-nullable type";
        // 如果有全局解释器锁
        if (has_gil) {
            // 设置内存错误异常消息
            PyErr_SetString(PyExc_MemoryError, msg);
        }
        else {
            // 否则,引发内存错误
            npy_gil_error(PyExc_MemoryError, msg);
        }
        // 返回加载失败状态
        return -1;
    }

    // 加载成功,返回成功状态
    return 0;
}
    else if (isnull) {
        // 如果数组中有空值
        if (has_null) {
            // 错误消息
            char *msg = "Arrays with missing data cannot be converted to a non-nullable type";
            // 如果已经获取了全局解释器锁
            if (has_gil)
            {
                // 设置 Python 异常对象为 ValueError,并传入错误消息
                PyErr_SetString(PyExc_ValueError, msg);
            }
            else {
                // 否则,调用 numpy 的 GIL 错误处理函数,设置 Python 异常为 ValueError,并传入错误消息
                npy_gil_error(PyExc_ValueError, msg);
            }
            // 返回 -1,表示操作失败
            return -1;
        }
        // 如果数组中没有空值,则将默认字符串复制到要加载的字符串中
        *string_to_load = *default_string;
    }
    // 操作成功,返回 0
    return 0;
// 这是一个静态函数,将非空字符串转换为 Python 字符串对象。
// 如果转换过程中遇到问题,返回 NULL。
static PyObject *
non_nullable_string_to_pystring(char *in, int has_null, const npy_static_string *default_string,
                                npy_string_allocator *allocator)
{
    // 创建一个静态字符串结构体 s,初始化为空
    npy_static_string s = {0, NULL};
    // 调用 load_non_nullable_string 函数,将输入的非空字符串转换为 s.buf 中的字符串
    if (load_non_nullable_string(in, has_null, default_string, &s, allocator, 1) == -1) {
        return NULL;
    }
    // 使用 s.buf 和 s.size 创建一个新的 Python Unicode 字符串对象
    PyObject *val_obj = PyUnicode_FromStringAndSize(s.buf, s.size);
    // 如果创建过程中出错,返回 NULL
    if (val_obj == NULL) {
        return NULL;
    }
    // 返回创建的 Python 字符串对象
    return val_obj;
}

// 这是一个静态函数,将字符串转换为 Python 长整型对象。
// 如果转换过程中遇到问题,返回 NULL。
static PyObject *
string_to_pylong(char *in, int has_null,
                 const npy_static_string *default_string,
                 npy_string_allocator *allocator)
{
    // 调用 non_nullable_string_to_pystring 函数,将输入的字符串转换为 Python 字符串对象
    PyObject *val_obj = non_nullable_string_to_pystring(
            in, has_null, default_string, allocator);
    // 如果转换过程中出错,返回 NULL
    if (val_obj == NULL) {
        return NULL;
    }
    // 将 Python 字符串对象解释为十进制整数
    PyObject *pylong_value = PyLong_FromUnicodeObject(val_obj, 10);
    // 减少对 val_obj 的引用计数
    Py_DECREF(val_obj);
    // 返回创建的 Python 长整型对象
    return pylong_value;
}

// 这是一个静态函数,将字符串转换为无符号长长整型数。
// 如果转换过程中出错,返回 -1;否则返回 0。
static npy_longlong
stringbuf_to_uint(char *in, npy_ulonglong *value, int has_null,
                  const npy_static_string *default_string,
                  npy_string_allocator *allocator)
{
    // 调用 string_to_pylong 函数,将输入的字符串转换为 Python 长整型对象
    PyObject *pylong_value =
            string_to_pylong(in, has_null, default_string, allocator);
    // 如果转换过程中出错,返回 -1
    if (pylong_value == NULL) {
        return -1;
    }
    // 将 Python 长整型对象转换为无符号长长整型数
    *value = PyLong_AsUnsignedLongLong(pylong_value);
    // 如果转换过程中出错,释放 Python 长整型对象并返回 -1
    if (*value == (unsigned long long)-1 && PyErr_Occurred()) {
        Py_DECREF(pylong_value);
        return -1;
    }
    // 释放 Python 长整型对象并返回 0
    Py_DECREF(pylong_value);
    return 0;
}

// 这是一个静态函数,将字符串转换为有符号长长整型数。
// 如果转换过程中出错,返回 -1;否则返回 0。
static npy_longlong
stringbuf_to_int(char *in, npy_longlong *value, int has_null,
                 const npy_static_string *default_string,
                 npy_string_allocator *allocator)
{
    // 调用 string_to_pylong 函数,将输入的字符串转换为 Python 长整型对象
    PyObject *pylong_value =
            string_to_pylong(in, has_null, default_string, allocator);
    // 如果转换过程中出错,返回 -1
    if (pylong_value == NULL) {
        return -1;
    }
    // 将 Python 长整型对象转换为有符号长长整型数
    *value = PyLong_AsLongLong(pylong_value);
    // 如果转换过程中出错,释放 Python 长整型对象并返回 -1
    if (*value == -1 && PyErr_Occurred()) {
        Py_DECREF(pylong_value);
        return -1;
    }
    // 释放 Python 长整型对象并返回 0
    Py_DECREF(pylong_value);
    return 0;
}

// 这是一个静态函数,将 Python 对象转换为字符串。
// 如果转换过程中出错,返回 -1;否则返回 0。
static int
pyobj_to_string(PyObject *obj, char *out, npy_string_allocator *allocator)
{
    // 如果输入的 Python 对象为空,返回 -1
    if (obj == NULL) {
        return -1;
    }
    // 将 Python 对象转换为字符串对象
    PyObject *pystr_val = PyObject_Str(obj);
    // 减少对输入 Python 对象的引用计数
    Py_DECREF(obj);

    // 如果转换过程中出错,返回 -1
    if (pystr_val == NULL) {
        return -1;
    }
    // 将 Python 字符串对象转换为 UTF-8 编码的 C 字符串
    Py_ssize_t length;
    const char *cstr_val = PyUnicode_AsUTF8AndSize(pystr_val, &length);
    // 如果转换过程中出错,释放 Python 字符串对象并返回 -1
    if (cstr_val == NULL) {
        Py_DECREF(pystr_val);
        return -1;
    }
    // 将 UTF-8 编码的 C 字符串打包到输出的字符串结构体中
    npy_packed_static_string *out_ss = (npy_packed_static_string *)out;
    if (NpyString_pack(allocator, out_ss, cstr_val, length) < 0) {
        // 如果打包过程中出错,报告内存错误,并释放 Python 字符串对象
        npy_gil_error(PyExc_MemoryError,
                      "Failed to pack string while converting from python "
                      "string");
        Py_DECREF(pystr_val);
        return -1;
    }
    // 释放 Python 字符串对象并返回 0
    Py_DECREF(pystr_val);
    return 0;
}
    // 递减 Python 对象的引用计数,当引用计数为零时自动释放对象
    Py_DECREF(pystr_val);
    // 返回整数 0,表示函数执行成功
    return 0;
}
// 结束静态函数定义

static int
int_to_stringbuf(long long in, char *out, npy_string_allocator *allocator)
{
    // 将 long long 类型的输入转换为 Python 的长整型对象
    PyObject *pylong_val = PyLong_FromLongLong(in);
    // 调用通用函数将 Python 对象转换为字符串,并使用分配器进行内存管理
    return pyobj_to_string(pylong_val, out, allocator);
}

static int
uint_to_stringbuf(unsigned long long in, char *out,
                  npy_string_allocator *allocator)
{
    // 将 unsigned long long 类型的输入转换为 Python 的无符号长整型对象
    PyObject *pylong_val = PyLong_FromUnsignedLongLong(in);
    // 调用通用函数将 Python 对象转换为字符串,并使用分配器进行内存管理
    return pyobj_to_string(pylong_val, out, allocator);
}

#define DTYPES_AND_CAST_SPEC(shortname, typename)                              \
        // 获取 string 到 typename 和 typename 到 string 的数据类型元信息
        PyArray_DTypeMeta **s2##shortname##_dtypes = get_dtypes(               \
                &PyArray_StringDType,                                          \
                &PyArray_##typename##DType);                                   \
                                                                               \
        // 获取 string 到 typename 的类型转换规范
        PyArrayMethod_Spec *StringTo##typename##CastSpec =                     \
                get_cast_spec(                                                 \
                        s2##shortname##_name, NPY_UNSAFE_CASTING,              \
                        NPY_METH_REQUIRES_PYAPI, s2##shortname##_dtypes,       \
                        s2##shortname##_slots);                                \
                                                                               \
        // 获取 typename 到 string 的类型转换规范
        PyArray_DTypeMeta **shortname##2s_dtypes = get_dtypes(                 \
                &PyArray_##typename##DType,                                    \
                &PyArray_StringDType);                                         \
                                                                               \
        // 获取 typename 到 string 的类型转换规范
        PyArrayMethod_Spec *typename##ToStringCastSpec = get_cast_spec(        \
                shortname##2s_name, NPY_SAFE_CASTING,                          \
                NPY_METH_REQUIRES_PYAPI, shortname##2s_dtypes,                 \
                shortname##2s_slots);

// 定义宏 DTYPES_AND_CAST_SPEC,用于生成不同类型之间的转换规范

STRING_INT_CASTS(int8, int, i8, NPY_INT8, lli, npy_longlong, long long)
// 宏 STRING_INT_CASTS 的实例化:定义 int8 类型转换规范

STRING_INT_CASTS(int16, int, i16, NPY_INT16, lli, npy_longlong, long long)
// 宏 STRING_INT_CASTS 的实例化:定义 int16 类型转换规范

STRING_INT_CASTS(int32, int, i32, NPY_INT32, lli, npy_longlong, long long)
// 宏 STRING_INT_CASTS 的实例化:定义 int32 类型转换规范

STRING_INT_CASTS(int64, int, i64, NPY_INT64, lli, npy_longlong, long long)
// 宏 STRING_INT_CASTS 的实例化:定义 int64 类型转换规范

STRING_INT_CASTS(uint8, uint, u8, NPY_UINT8, llu, npy_ulonglong,
                 unsigned long long)
// 宏 STRING_INT_CASTS 的实例化:定义 uint8 类型转换规范

STRING_INT_CASTS(uint16, uint, u16, NPY_UINT16, llu, npy_ulonglong,
                 unsigned long long)
// 宏 STRING_INT_CASTS 的实例化:定义 uint16 类型转换规范

STRING_INT_CASTS(uint32, uint, u32, NPY_UINT32, llu, npy_ulonglong,
                 unsigned long long)
// 宏 STRING_INT_CASTS 的实例化:定义 uint32 类型转换规范

STRING_INT_CASTS(uint64, uint, u64, NPY_UINT64, llu, npy_ulonglong,
                 unsigned long long)
// 宏 STRING_INT_CASTS 的实例化:定义 uint64 类型转换规范

#if NPY_SIZEOF_BYTE == NPY_SIZEOF_SHORT
// 如果 byte 的大小等于 short 的大小

// 宏 STRING_INT_CASTS 的实例化:定义 byte 类型转换规范
STRING_INT_CASTS(byte, int, byte, NPY_BYTE, lli, npy_longlong, long long)

// 宏 STRING_INT_CASTS 的实例化:定义 ubyte 类型转换规范
STRING_INT_CASTS(ubyte, uint, ubyte, NPY_UBYTE, llu, npy_ulonglong,
                 unsigned long long)
#endif

#if NPY_SIZEOF_SHORT == NPY_SIZEOF_INT
// 如果 short 的大小等于 int 的大小
// 定义宏,用于生成字符串到整数类型的转换函数和相关信息的结构体定义
#define STRING_INT_CASTS(typename, shortname, isinf_name, npy_typename,    \
                         lli, npy_longlong, long long)                     \
    // 定义函数 string_to_##typename,用于将字符串转换为整数类型
    static int string_to_##typename(PyArrayMethod_Context * context,       \
                                    char *const data[],                    \
                                    npy_intp const dimensions[],           \
                                    npy_intp const strides[],              \
                                    NpyAuxData *NPY_UNUSED(auxdata))      \
    // 定义失败处理标签 fail,用于在出错时释放分配的字符串内存并返回错误
    fail:                                                                 \
        NpyString_release_allocator(allocator);                           \
        return -1;                                                        \
    }                                                                     \
                                                                          \
    // 定义 PyType_Slot 结构体数组 s2##shortname##_slots,包含函数指针和描述符解析方法
    static PyType_Slot s2##shortname##_slots[] = {                        \
            // 解析描述符方法,关联到函数 string_to_##typename##_resolve_descriptors
            {NPY_METH_resolve_descriptors,                                \
             &string_to_##typename##_resolve_descriptors},                \
            // 循环方法,关联到函数 string_to_##typename
            {NPY_METH_strided_loop, &string_to_##typename},               \
            // 结束标记
            {0, NULL}};                                                   \
                                                                          \
    // 定义字符串常量 s2##shortname##_name,描述类型转换的名称
    static char *s2##shortname##_name = "cast_StringDType_to_" #typename;

// 定义宏,用于生成字符串到浮点数类型的转换函数和相关信息的结构体定义
#define STRING_TO_FLOAT_CAST(typename, shortname, isinf_name,             \
                             double_to_float)                             \
    // 定义函数 string_to_##typename,用于将字符串转换为浮点数类型
    static int string_to_##typename(PyArrayMethod_Context * context,       \
                                    char *const data[],                    \
                                    npy_intp const dimensions[],           \
                                    npy_intp const strides[],              \
                                    NpyAuxData *NPY_UNUSED(auxdata))      \
    // 定义失败处理标签 fail,用于在出错时释放分配的字符串内存并返回错误
    fail:                                                                 \
        NpyString_release_allocator(allocator);                           \
        return -1;                                                        \
    }                                                                     \
                                                                          \
    // 定义 PyType_Slot 结构体数组 s2##shortname##_slots,包含函数指针和描述符解析方法
    static PyType_Slot s2##shortname##_slots[] = {                        \
            // 解析描述符方法,关联到函数 string_to_##typename##_resolve_descriptors
            {NPY_METH_resolve_descriptors,                                \
             &string_to_##typename##_resolve_descriptors},                \
            // 循环方法,关联到函数 string_to_##typename
            {NPY_METH_strided_loop, &string_to_##typename},               \
            // 结束标记
            {0, NULL}};                                                   \
                                                                          \
    // 定义字符串常量 s2##shortname##_name,描述类型转换的名称
    static char *s2##shortname##_name = "cast_StringDType_to_" #typename;

// 空的宏定义,用于未实现的宏参数
#define STRING_TO_FLOAT_RESOLVE_DESCRIPTORS(typename, npy_typename)
    // 定义一个静态函数 string_to_##typename##_resolve_descriptors,
    // 该函数用于解析描述符并进行类型转换
    static NPY_CASTING string_to_##typename##_resolve_descriptors(         \
            // 不使用 self 参数
            PyObject *NPY_UNUSED(self),                                    \
            // 不使用 dtypes 数组
            PyArray_DTypeMeta *NPY_UNUSED(dtypes[2]),                      \
            // 输入的描述符数组和循环使用的描述符数组
            PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2], \
            // 视图偏移量,不使用此参数
            npy_intp *NPY_UNUSED(view_offset))                             \
    {                                                                      \
        // 如果第二个给定的描述符为空
        if (given_descrs[1] == NULL) {                                     \
            // 根据给定的 numpy 类型创建新的描述符并存储在循环描述符数组中
            loop_descrs[1] = PyArray_DescrNewFromType(NPY_##npy_typename); \
        }                                                                  \
        else {                                                             \
            // 增加给定描述符的引用计数并复制到循环描述符数组中
            Py_INCREF(given_descrs[1]);                                    \
            loop_descrs[1] = given_descrs[1];                              \
        }                                                                  \
                                                                           \
        // 增加给定描述符的引用计数并复制到循环描述符数组中
        Py_INCREF(given_descrs[0]);                                        \
        loop_descrs[0] = given_descrs[0];                                  \
                                                                           \
        // 返回非安全转换标志
        return NPY_UNSAFE_CASTING;                                         \
    }
// 定义宏 FLOAT_TO_STRING_CAST,用于生成将特定类型的数组转换为字符串的函数
#define FLOAT_TO_STRING_CAST(typename, shortname, float_to_double)            \
    // 定义函数 typename##_to_string,用于将特定类型的数组转换为字符串
    static int typename##_to_string(                                          \
            PyArrayMethod_Context *context, char *const data[],               \
            npy_intp const dimensions[], npy_intp const strides[],            \
            NpyAuxData *NPY_UNUSED(auxdata))                                  \
    {                                                                         \
        // 获取数组的第一个维度大小
        npy_intp N = dimensions[0];                                           \
        // 将输入数据解释为指定类型的数组
        npy_##typename *in = (npy_##typename *)data[0];                       \
        // 输出字符串的起始位置
        char *out = data[1];                                                  \
        // 获取浮点数的描述器
        PyArray_Descr *float_descr = context->descriptors[0];                 \
                                                                              \
        // 计算输入数组的步长(每个元素占据的字节数除以数据类型的大小)
        npy_intp in_stride = strides[0] / sizeof(npy_##typename);             \
        // 输出数组的步长
        npy_intp out_stride = strides[1];                                     \
                                                                              \
        // 获取输出字符串的描述器对象
        PyArray_StringDTypeObject *descr =                                    \
                (PyArray_StringDTypeObject *)context->descriptors[1];         \
        // 获取字符串分配器
        npy_string_allocator *allocator = NpyString_acquire_allocator(descr); \
                                                                              \
        // 循环处理每个元素
        while (N--) {                                                         \
            // 将输入数组中的当前值转换为 Python 对象
            PyObject *scalar_val = PyArray_Scalar(in, float_descr, NULL);     \
            // 将 Python 对象转换为字符串并存储到输出位置,使用指定的分配器
            if (pyobj_to_string(scalar_val, out, allocator) == -1) {          \
                // 转换失败时跳转到失败处理标签
                goto fail;                                                    \
            }                                                                 \
                                                                              \
            // 更新输入和输出指针到下一个元素
            in += in_stride;                                                  \
            out += out_stride;                                                \
        }                                                                     \
                                                                              \
        // 释放字符串分配器
        NpyString_release_allocator(allocator);                               \
        // 返回成功状态
        return 0;                                                             \
    fail:                                                                     \
        // 失败时释放字符串分配器并返回失败状态
        NpyString_release_allocator(allocator);                               \
        return -1;                                                            \
    }
    // 定义 PyType_Slot 结构体数组,用于实现类型转换
    static PyType_Slot shortname##2s_slots [] = {                             \
            // 设置解析描述符方法,指向 any_to_string_SAFE_resolve_descriptors 函数
            {NPY_METH_resolve_descriptors,                                    \
             &any_to_string_SAFE_resolve_descriptors},                        \
            // 设置跨步循环方法,指向 typename##_to_string 函数
            {NPY_METH_strided_loop, &typename##_to_string},                   \
            // 终止标记,空槽和空指针
            {0, NULL}};                                                       \
                                                                              \
        // 定义 shortname##2s_name,表示类型转换的名称字符串
        static char *shortname##2s_name = "cast_" #typename "_to_StringDType";
# 解析指定的宏并生成相应的函数描述符(例如 float64 对应的 DOUBLE)
STRING_TO_FLOAT_RESOLVE_DESCRIPTORS(float64, DOUBLE)

# 定义将字符串转换为 float64 的函数
static int
string_to_float64(PyArrayMethod_Context *context, char *const data[],
                  npy_intp const dimensions[], npy_intp const strides[],
                  NpyAuxData *NPY_UNUSED(auxdata))
{
    # 获取描述符对象,用于描述字符串的数据类型
    PyArray_StringDTypeObject *descr = (PyArray_StringDTypeObject *)context->descriptors[0];
    # 获取字符串分配器
    npy_string_allocator *allocator = NpyString_acquire_allocator(descr);
    # 检查是否存在 null 值标记
    int has_null = descr->na_object != NULL;
    # 获取默认字符串
    const npy_static_string *default_string = &descr->default_string;
    # 获取处理的数据点数
    npy_intp N = dimensions[0];
    # 输入数据的起始位置
    char *in = data[0];
    # 输出数据的起始位置(转换为 float64 类型)
    npy_float64 *out = (npy_float64 *)data[1];

    # 输入数据和输出数据的步长
    npy_intp in_stride = strides[0];
    npy_intp out_stride = strides[1] / sizeof(npy_float64);

    # 迭代处理每个数据点
    while (N--) {
        # 将输入字符串转换为 Python 的 float 对象
        PyObject *pyfloat_value =
                string_to_pyfloat(in, has_null, default_string, allocator);
        # 如果转换失败,则跳转到错误处理标签
        if (pyfloat_value == NULL) {
            goto fail;
        }
        # 将 Python float 对象的值转换为 npy_float64 类型并存入输出数组
        *out = (npy_float64)PyFloat_AS_DOUBLE(pyfloat_value);
        # 减少 Python float 对象的引用计数
        Py_DECREF(pyfloat_value);

        # 更新输入数据指针位置和输出数据指针位置
        in += in_stride;
        out += out_stride;
    }

    # 释放字符串分配器
    NpyString_release_allocator(allocator);
    return 0;

fail:
    # 失败时释放字符串分配器并返回错误码
    NpyString_release_allocator(allocator);
    return -1;
}

# 定义 float64 类型的方法槽
static PyType_Slot s2f64_slots[] = {
        {NPY_METH_resolve_descriptors, &string_to_float64_resolve_descriptors},
        {NPY_METH_strided_loop, &string_to_float64},
        {0, NULL}};

# 定义 float64 类型的名称
static char *s2f64_name = "cast_StringDType_to_float64";

# 定义将 float64 转换为字符串的宏和函数
FLOAT_TO_STRING_CAST(float64, f64, double)

# 解析指定的宏并生成相应的函数描述符(例如 float32 对应的 FLOAT)
STRING_TO_FLOAT_RESOLVE_DESCRIPTORS(float32, FLOAT)

# 定义将字符串转换为 float32 的宏和函数
STRING_TO_FLOAT_CAST(float32, f32, npy_isinf, npy_float32)
# 定义将 float32 转换为字符串的宏和函数
FLOAT_TO_STRING_CAST(float32, f32, double)

# 解析指定的宏并生成相应的函数描述符(例如 float16 对应的 HALF)
STRING_TO_FLOAT_RESOLVE_DESCRIPTORS(float16, HALF)

# 定义将字符串转换为 float16 的宏和函数
STRING_TO_FLOAT_CAST(float16, f16, npy_half_isinf, npy_double_to_half)
# 定义将 float16 转换为字符串的宏和函数
FLOAT_TO_STRING_CAST(float16, f16, npy_half_to_double)

# 解析指定的宏并生成相应的函数描述符(例如 longdouble 对应的 LONGDOUBLE)
STRING_TO_FLOAT_RESOLVE_DESCRIPTORS(longdouble, LONGDOUBLE);

# 定义将字符串转换为 longdouble 的函数
static int
string_to_longdouble(PyArrayMethod_Context *context, char *const data[],
                     npy_intp const dimensions[], npy_intp const strides[],
                     NpyAuxData *NPY_UNUSED(auxdata))
{
    # 获取描述符对象,用于描述字符串的数据类型
    PyArray_StringDTypeObject *descr = (PyArray_StringDTypeObject *)context->descriptors[0];
    # 获取字符串分配器
    npy_string_allocator *allocator = NpyString_acquire_allocator(descr);
    # 检查是否存在 null 值标记
    int has_null = descr->na_object != NULL;
    # 获取默认字符串
    const npy_static_string *default_string = &descr->default_string;
    # 获取处理的数据点数
    npy_intp N = dimensions[0];
    # 输入数据的起始位置
    char *in = data[0];
    # 输出数据的起始位置(转换为 longdouble 类型)
    npy_longdouble *out = (npy_longdouble *)data[1];

    # 输入数据和输出数据的步长
    npy_intp in_stride = strides[0];
    npy_intp out_stride = strides[1] / sizeof(npy_longdouble);
    // 循环,逐个处理直到 N 减少为零
    while (N--) {
        // 定义静态字符串结构体并初始化为空
        npy_static_string s = {0, NULL};
        // 尝试从输入流中加载非空字符串,如果失败则跳转到失败标签
        if (load_non_nullable_string(in, has_null, default_string, &s, allocator, 0) == -1) {
            goto fail;
        }

        // 分配临时的以 null 结尾的字符串拷贝
        char *buf = PyMem_RawMalloc(s.size + 1);
        memcpy(buf, s.buf, s.size);
        buf[s.size] = '\0';

        // 解析 buf 中的字符串为长双精度浮点数
        char *end = NULL;
        errno = 0;
        npy_longdouble longdouble_value = NumPyOS_ascii_strtold(buf, &end);

        // 检查是否出现了范围错误
        if (errno == ERANGE) {
            /* strtold 返回正确符号的无穷大。如果警告触发失败则释放内存并跳转到失败标签 */
            if (PyErr_Warn(PyExc_RuntimeWarning,
                           "overflow encountered in conversion from string") < 0) {
                PyMem_RawFree(buf);
                goto fail;
            }
        }
        // 检查是否出现了其他错误或者未成功解析完整个字符串
        else if (errno || end == buf || *end) {
            PyErr_Format(PyExc_ValueError,
                         "invalid literal for long double: %s (%s)",
                         buf,
                         strerror(errno));
            PyMem_RawFree(buf);
            goto fail;
        }
        PyMem_RawFree(buf);  // 释放 buf 的内存
        *out = longdouble_value;  // 将解析得到的长双精度浮点数存入 out 指向的位置

        // 更新输入和输出指针位置
        in += in_stride;
        out += out_stride;
    }

    // 释放分配器所使用的字符串分配器
    NpyString_release_allocator(allocator);
    return 0;
fail:
    // 释放字符串分配器,并返回-1表示失败
    NpyString_release_allocator(allocator);
    return -1;
}

static PyType_Slot s2ld_slots[] = {
    {NPY_METH_resolve_descriptors, &string_to_longdouble_resolve_descriptors},
    {NPY_METH_strided_loop, &string_to_longdouble},
    {0, NULL}
};

static char *s2ld_name = "cast_StringDType_to_longdouble";

// 将 longdouble 转换为字符串

// TODO: 这里是不正确的。longdouble 到 unicode 的转换也有同样的问题。要修复这个问题,我们需要在 NumPy 中实现 ldtoa 函数。它并不在标准库中。另一个选项是使用 `snprintf`,但我们需要预先计算结果字符串的大小。

FLOAT_TO_STRING_CAST(longdouble, ld, npy_longdouble)

// 将字符串转换为 cfloat

static PyObject*
string_to_pycomplex(char *in, int has_null,
                    const npy_static_string *default_string,
                    npy_string_allocator *allocator)
{
    PyObject *val_obj = non_nullable_string_to_pystring(
            in, has_null, default_string, allocator);
    if (val_obj == NULL) {
        return NULL;
    }
    PyObject *args = PyTuple_Pack(1, val_obj);
    Py_DECREF(val_obj);
    if (args == NULL) {
        return NULL;
    }
    PyObject *pycomplex_value = PyComplex_Type.tp_new(&PyComplex_Type, args, NULL);
    Py_DECREF(args);
    return pycomplex_value;
}

fail:                                                                            \
    // 释放字符串分配器,并返回-1表示失败
    NpyString_release_allocator(allocator);                                  \
    return -1;                                                               \
    }                                                                        \
                                                                                 \
    static PyType_Slot s2##ctype##_slots[] = {                               \
        {NPY_METH_resolve_descriptors,                                   \
         &string_to_##ctype##_resolve_descriptors},                      \
        {NPY_METH_strided_loop, &string_to_##ctype},                     \
        {0, NULL}};                                                      \
                                                                                 \
    static char *s2##ctype##_name = "cast_StringDType_to_" #ctype;

STRING_TO_FLOAT_RESOLVE_DESCRIPTORS(cfloat, CFLOAT)
STRING_TO_CFLOAT_CAST(cfloat, f, float)

// 将 cfloat 转换为字符串

FLOAT_TO_STRING_CAST(cfloat, cfloat, npy_cfloat)

// 将字符串转换为 cdouble

STRING_TO_FLOAT_RESOLVE_DESCRIPTORS(cdouble, CDOUBLE)
STRING_TO_CFLOAT_CAST(cdouble, , double)

// 将 cdouble 转换为字符串

FLOAT_TO_STRING_CAST(cdouble, cdouble, npy_cdouble)

// 将字符串转换为 clongdouble

STRING_TO_FLOAT_RESOLVE_DESCRIPTORS(clongdouble, CLONGDOUBLE)
STRING_TO_CFLOAT_CAST(clongdouble, l, longdouble)

// 将 longdouble 转换为字符串

FLOAT_TO_STRING_CAST(clongdouble, clongdouble, npy_clongdouble)

// 将字符串转换为 datetime

static NPY_CASTING
// 如果给定描述符的第二个元素为NULL,表示没有指定时间单位,抛出类型错误异常并返回-1
string_to_datetime_timedelta_resolve_descriptors(
        PyObject *NPY_UNUSED(self), PyArray_DTypeMeta *NPY_UNUSED(dtypes[2]),
        PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2],
        npy_intp *NPY_UNUSED(view_offset))
{
    if (given_descrs[1] == NULL) {
        PyErr_SetString(PyExc_TypeError,
                        "Casting from StringDType to datetimes without a unit "
                        "is not currently supported");
        return (NPY_CASTING)-1;
    }
    else {
        // 增加给定描述符的引用计数,并将其赋值给循环描述符的第二个元素
        Py_INCREF(given_descrs[1]);
        loop_descrs[1] = given_descrs[1];
    }

    // 增加给定描述符的引用计数,并将其赋值给循环描述符的第一个元素
    Py_INCREF(given_descrs[0]);
    loop_descrs[0] = given_descrs[0];

    // 返回安全类型转换标志
    return NPY_UNSAFE_CASTING;
}

// numpy将空字符串和字符串'nat'的任何大小写组合视为字符串转换中NaT的等价形式
static int
is_nat_string(const npy_static_string *s) {
    // 如果字符串长度为0或者长度为3且内容为'nat'(不区分大小写),则返回真
    return s->size == 0 || (s->size == 3 &&
             NumPyOS_ascii_tolower(s->buf[0]) == 'n' &&
             NumPyOS_ascii_tolower(s->buf[1]) == 'a' &&
             NumPyOS_ascii_tolower(s->buf[2]) == 't');
}

// 将字符串转换为日期时间
static int
string_to_datetime(PyArrayMethod_Context *context, char *const data[],
                   npy_intp const dimensions[], npy_intp const strides[],
                   NpyAuxData *NPY_UNUSED(auxdata))
{
    // 获取描述符对象
    PyArray_StringDTypeObject *descr = (PyArray_StringDTypeObject *)context->descriptors[0];
    // 获取字符串分配器
    npy_string_allocator *allocator = NpyString_acquire_allocator(descr);
    // 检查是否存在空值对象
    int has_null = descr->na_object != NULL;
    // 检查是否有字符串NA
    int has_string_na = descr->has_string_na;
    // 默认字符串
    const npy_static_string *default_string = &descr->default_string;

    // 获取第一维度大小
    npy_intp N = dimensions[0];
    // 输入数据指针
    char *in = data[0];
    // 输出数据指针(日期时间类型)
    npy_datetime *out = (npy_datetime *)data[1];

    // 输入数据步长
    npy_intp in_stride = strides[0];
    // 输出数据步长(转换为日期时间类型)
    npy_intp out_stride = strides[1] / sizeof(npy_datetime);

    // 日期时间结构体
    npy_datetimestruct dts;
    // 输入单位
    NPY_DATETIMEUNIT in_unit = -1;
    // 输入元数据
    PyArray_DatetimeMetaData in_meta = {0, 1};
    // 输出是否特殊值
    npy_bool out_special;

    // 获取日期时间描述符对象
    _PyArray_LegacyDescr *dt_descr = (_PyArray_LegacyDescr *)context->descriptors[1];
    // 获取日期时间元数据
    PyArray_DatetimeMetaData *dt_meta =
            &(((PyArray_DatetimeDTypeMetaData *)dt_descr->c_metadata)->meta);
    # 使用 while 循环逐步处理每个输入的字符串
    while (N--) {
        # 将输入的字节序列解释为静态字符串结构
        const npy_packed_static_string *ps = (npy_packed_static_string *)in;
        # 初始化静态字符串 s
        npy_static_string s = {0, NULL};
        # 调用 NpyString_load 函数加载静态字符串,检查是否为空
        int is_null = NpyString_load(allocator, ps, &s);
        # 如果加载过程中出现错误,设置内存错误并跳转到失败处理代码块
        if (is_null == -1) {
            PyErr_SetString(
                    PyExc_MemoryError,
                    "Failed to load string in string to datetime cast");
            goto fail;
        }
        # 如果字符串为空
        if (is_null) {
            # 如果存在空值并且未指定字符串的 NA 值,设置输出为 NPY_DATETIME_NAT,并跳转到下一步
            if (has_null && !has_string_na) {
                *out = NPY_DATETIME_NAT;
                goto next_step;
            }
            # 否则使用默认字符串作为 s 的值
            s = *default_string;
        }
        # 如果字符串表示为 'NaT',设置输出为 NPY_DATETIME_NAT,并跳转到下一步
        if (is_nat_string(&s)) {
            *out = NPY_DATETIME_NAT;
            goto next_step;
        }

        // 实际解析日期时间字符串
        // 调用 NpyDatetime_ParseISO8601Datetime 函数解析 ISO 8601 格式的日期时间字符串
        if (NpyDatetime_ParseISO8601Datetime(
                    (const char *)s.buf, s.size, in_unit, NPY_UNSAFE_CASTING,
                    &dts, &in_meta.base, &out_special) < 0) {
            goto fail;
        }
        // 将日期时间结构转换为 datetime64 类型
        if (NpyDatetime_ConvertDatetimeStructToDatetime64(dt_meta, &dts, out) <
            0) {
            goto fail;
        }

    next_step:
        # 更新输入和输出指针位置
        in += in_stride;
        out += out_stride;
    }

    # 释放字符串分配器的资源
    NpyString_release_allocator(allocator);
    # 返回操作成功的标志
    return 0;
// 释放内存分配器并返回错误代码
fail:
    NpyString_release_allocator(allocator);
    return -1;
}

// 定义 PyType_Slot 结构数组,描述 s2dt 对象的行为
static PyType_Slot s2dt_slots[] = {
        // 解析描述符方法
        {NPY_METH_resolve_descriptors,
         &string_to_datetime_timedelta_resolve_descriptors},
        // 循环处理方法
        {NPY_METH_strided_loop, &string_to_datetime},
        // 数组结束标志
        {0, NULL}};

// 字符串变换为日期时间的名称
static char *s2dt_name = "cast_StringDType_to_Datetime";

// datetime 转换为字符串

static int
datetime_to_string(PyArrayMethod_Context *context, char *const data[],
                   npy_intp const dimensions[], npy_intp const strides[],
                   NpyAuxData *NPY_UNUSED(auxdata))
{
    // 获取数组维度
    npy_intp N = dimensions[0];
    // 输入数据的指针
    npy_datetime *in = (npy_datetime *)data[0];
    // 输出数据的指针
    char *out = data[1];

    // 输入数据的步幅
    npy_intp in_stride = strides[0] / sizeof(npy_datetime);
    // 输出数据的步幅
    npy_intp out_stride = strides[1];

    // 获取日期时间描述符
    _PyArray_LegacyDescr *dt_descr = (_PyArray_LegacyDescr *)context->descriptors[0];
    // 获取日期时间元数据
    PyArray_DatetimeMetaData *dt_meta =
            &(((PyArray_DatetimeDTypeMetaData *)dt_descr->c_metadata)->meta);
    // 用于构建日期时间字符串的缓冲区
    char datetime_buf[NPY_DATETIME_MAX_ISO8601_STRLEN];

    // 获取字符串描述符
    PyArray_StringDTypeObject *sdescr = (PyArray_StringDTypeObject *)context->descriptors[1];
    // 检查是否有空值对象
    int has_null = sdescr->na_object != NULL;
    // 获取字符串分配器
    npy_string_allocator *allocator = NpyString_acquire_allocator(sdescr);
    while (N--) {
        npy_packed_static_string *out_pss = (npy_packed_static_string *)out;
        // 如果输入值为 NaT (Not a Time),处理特殊情况
        if (*in == NPY_DATETIME_NAT)
        {
            // 如果没有空值,将字符串 "NaT" 打包到输出结构中
            if (!has_null) {
                npy_static_string os = {3, "NaT"};
                // 调用 NpyString_pack 函数尝试将 "NaT" 打包到输出结构
                if (NpyString_pack(allocator, out_pss, os.buf, os.size) < 0) {
                    // 若失败,抛出内存错误并跳转到失败处理标签
                    npy_gil_error(
                            PyExc_MemoryError,
                            "Failed to pack string in datetime to string "
                            "cast");
                    goto fail;
                }
            }
            // 如果有空值,调用 NpyString_pack_null 函数将空值打包到输出结构
            else if (NpyString_pack_null(allocator, out_pss) < 0) {
                // 若失败,抛出内存错误并跳转到失败处理标签
                npy_gil_error(
                        PyExc_MemoryError,
                        "Failed to pack string in datetime to string cast");
                goto fail;
            }
        }
        // 对于正常日期时间值,进行格式转换并打包到输出结构
        else {
            npy_datetimestruct dts;
            // 将输入日期时间值转换为日期时间结构
            if (NpyDatetime_ConvertDatetime64ToDatetimeStruct(
                        dt_meta, *in, &dts) < 0) {
                // 若转换失败,跳转到失败处理标签
                goto fail;
            }

            // 将日期时间缓冲区清零
            memset(datetime_buf, 0, NPY_DATETIME_MAX_ISO8601_STRLEN);

            // 将日期时间结构转换为 ISO8601 格式的字符串
            if (NpyDatetime_MakeISO8601Datetime(
                        &dts, datetime_buf, NPY_DATETIME_MAX_ISO8601_STRLEN, 0,
                        0, dt_meta->base, -1, NPY_UNSAFE_CASTING) < 0) {
                // 若转换失败,跳转到失败处理标签
                goto fail;
            }

            // 将转换后的 ISO8601 格式字符串打包到输出结构
            if (NpyString_pack(allocator, out_pss, datetime_buf,
                               strlen(datetime_buf)) < 0) {
                // 若打包失败,设置异常并跳转到失败处理标签
                PyErr_SetString(PyExc_MemoryError,
                                "Failed to pack string while converting "
                                "from a datetime.");
                goto fail;
            }
        }

        // 更新输入和输出指针位置
        in += in_stride;
        out += out_stride;
    }

    // 释放分配器资源
    NpyString_release_allocator(allocator);
    // 返回成功状态
    return 0;
fail:
    // 释放字符串分配器的资源
    NpyString_release_allocator(allocator);
    // 返回-1,表示函数执行失败
    return -1;
}

static PyType_Slot dt2s_slots[] = {
        // 方法插槽:解析描述符,使用安全版本的任意类型到字符串转换方法
        {NPY_METH_resolve_descriptors,
         &any_to_string_SAFE_resolve_descriptors},
        // 方法插槽:使用日期时间对象进行跨步循环的字符串转换
        {NPY_METH_strided_loop, &datetime_to_string},
        {0, NULL}};

static char *dt2s_name = "cast_Datetime_to_StringDType";

// string to timedelta

static int
string_to_timedelta(PyArrayMethod_Context *context, char *const data[],
                    npy_intp const dimensions[], npy_intp const strides[],
                    NpyAuxData *NPY_UNUSED(auxdata))
{
    // 获取字符串数据类型的描述符对象
    PyArray_StringDTypeObject *descr = (PyArray_StringDTypeObject *)context->descriptors[0];
    // 获取字符串分配器
    npy_string_allocator *allocator = NpyString_acquire_allocator(descr);
    // 判断是否有空值对象
    int has_null = descr->na_object != NULL;
    // 判断是否包含字符串 NA
    int has_string_na = descr->has_string_na;
    // 默认字符串
    const npy_static_string *default_string = &descr->default_string;

    // 数据维度
    npy_intp N = dimensions[0];
    // 输入数据指针
    char *in = data[0];
    // 输出数据指针
    npy_timedelta *out = (npy_timedelta *)data[1];

    // 输入和输出的步长
    npy_intp in_stride = strides[0];
    npy_intp out_stride = strides[1] / sizeof(npy_timedelta);

    // 循环处理每个元素
    while (N--) {
        // 转换为紧凑静态字符串对象
        const npy_packed_static_string *ps = (npy_packed_static_string *)in;
        // 静态字符串对象
        npy_static_string s = {0, NULL};
        // 加载字符串并检查是否为空
        int is_null = NpyString_load(allocator, ps, &s);
        // 如果加载失败,设置内存错误并跳转到错误处理标签
        if (is_null == -1) {
            PyErr_SetString(
                    PyExc_MemoryError,
                    "Failed to load string in string to datetime cast");
            goto fail;
        }
        // 如果是空字符串
        if (is_null) {
            // 如果允许空值且不包含字符串 NA,设置为默认字符串
            if (has_null && !has_string_na) {
                *out = NPY_DATETIME_NAT;
                goto next_step;
            }
            s = *default_string;
        }
        // 如果是 NA 字符串
        if (is_nat_string(&s)) {
            *out = NPY_DATETIME_NAT;
            goto next_step;
        }

        // 从静态字符串创建 Python Unicode 对象
        PyObject *pystr = PyUnicode_FromStringAndSize(s.buf, s.size);
        if (pystr == NULL) {
            goto fail;
        }

        // 解释为十进制整数
        PyObject *pylong_value = PyLong_FromUnicodeObject(pystr, 10);
        Py_DECREF(pystr);
        if (pylong_value == NULL) {
            goto fail;
        }

        // 将 Python 长整型对象转换为 C 长整型
        npy_longlong value = PyLong_AsLongLong(pylong_value);
        Py_DECREF(pylong_value);
        if (value == -1 && PyErr_Occurred()) {
            goto fail;
        }

        // 将结果赋给输出的 timedelta 数组
        *out = (npy_timedelta)value;

    next_step:
        // 移动输入和输出指针到下一个元素
        in += in_stride;
        out += out_stride;
    }

    // 释放字符串分配器的资源
    NpyString_release_allocator(allocator);
    // 返回成功
    return 0;

fail:
    // 释放字符串分配器的资源
    NpyString_release_allocator(allocator);
    // 返回失败
    return -1;
}

static PyType_Slot s2td_slots[] = {
        // 方法插槽:解析描述符,使用字符串到日期时间类型转换的描述符
        {NPY_METH_resolve_descriptors,
         &string_to_datetime_timedelta_resolve_descriptors},
        // 方法插槽:使用字符串到 timedelta 类型的转换方法
        {NPY_METH_strided_loop, &string_to_timedelta},
        {0, NULL}};

static char *s2td_name = "cast_StringDType_to_Timedelta";

// timedelta to string

static int
// 将 timedelta 转换为字符串
timedelta_to_string(PyArrayMethod_Context *context, char *const data[],
                   npy_intp const dimensions[], npy_intp const strides[],
                   NpyAuxData *NPY_UNUSED(auxdata))
{
    // 获取第一个维度的大小
    npy_intp N = dimensions[0];
    // 获取输入数据指针,并转换为 npy_timedelta 类型
    npy_timedelta *in = (npy_timedelta *)data[0];
    // 获取输出数据指针
    char *out = data[1];

    // 计算输入数据的步长和输出数据的步长
    npy_intp in_stride = strides[0] / sizeof(npy_timedelta);
    npy_intp out_stride = strides[1];

    // 获取字符串类型描述符
    PyArray_StringDTypeObject *sdescr = (PyArray_StringDTypeObject *)context->descriptors[1];
    // 检查是否有空值对象
    int has_null = sdescr->na_object != NULL;
    // 获取字符串分配器
    npy_string_allocator *allocator = NpyString_acquire_allocator(sdescr);

    // 循环处理每个元素
    while (N--) {
        // 输出数据的静态字符串指针
        npy_packed_static_string *out_pss = (npy_packed_static_string *)out;
        // 如果输入是 NaT(Not a Time),处理特殊情况
        if (*in == NPY_DATETIME_NAT)
        {
            // 如果没有空值对象,将 "NaT" 打包到输出静态字符串中
            if (!has_null) {
                npy_static_string os = {3, "NaT"};
                // 使用字符串分配器打包字符串到输出静态字符串指针中
                if (NpyString_pack(allocator, out_pss, os.buf, os.size) < 0) {
                    // 如果打包失败,抛出内存错误并跳转到失败处理标签
                    npy_gil_error(
                            PyExc_MemoryError,
                            "Failed to pack string in timedelta to string "
                            "cast");
                    goto fail;
                }
            }
            // 如果有空值对象,使用 NpyString_pack_null 函数打包空值对象
            else if (NpyString_pack_null(allocator, out_pss) < 0) {
                npy_gil_error(
                        PyExc_MemoryError,
                        "Failed to pack string in timedelta to string cast");
                goto fail;
            }
        }
        // 如果输入不是 NaT,则将其转换为字符串并存储到输出中
        else if (int_to_stringbuf((long long)*in, out, allocator) < 0) {
            // 如果转换失败,跳转到失败处理标签
            goto fail;
        }

        // 更新输入和输出指针
        in += in_stride;
        out += out_stride;
    }

    // 释放字符串分配器
    NpyString_release_allocator(allocator);
    // 返回成功标志
    return 0;

fail:
    // 失败时释放字符串分配器并返回错误标志
    NpyString_release_allocator(allocator);
    return -1;
}

// timedelta 转换为字符串的方法槽
static PyType_Slot td2s_slots[] = {
        {NPY_METH_resolve_descriptors,
         &any_to_string_SAFE_resolve_descriptors},
        {NPY_METH_strided_loop, &timedelta_to_string},
        {0, NULL}};

// timedelta 转换为字符串的名称
static char *td2s_name = "cast_Timedelta_to_StringDType";

// 字符串到空值的方法:解析描述符
static NPY_CASTING
string_to_void_resolve_descriptors(PyObject *NPY_UNUSED(self),
                                   PyArray_DTypeMeta *NPY_UNUSED(dtypes[2]),
                                   PyArray_Descr *given_descrs[2],
                                   PyArray_Descr *loop_descrs[2],
                                   npy_intp *NPY_UNUSED(view_offset))
{
    // 如果给定的描述符为空,抛出类型错误并返回错误标志
    if (given_descrs[1] == NULL) {
        PyErr_SetString(
                PyExc_TypeError,
                "Casting from StringDType to a fixed-width dtype with an "
                "unspecified size is not currently supported, specify "
                "an explicit size for the output dtype instead.");
        return (NPY_CASTING)-1;
    }


这些注释解释了每行代码的作用和功能,按照要求将其包含在代码块中。
    else {
        // 如果给定描述符的类型为结构化空类型,则拒绝
        if (PyDataType_NAMES(given_descrs[1]) != NULL || PyDataType_SUBARRAY(given_descrs[1]) != NULL) {
            // 设置类型错误异常,说明从 StringDType 转换到结构化 dtype 是不支持的
            PyErr_SetString(
                    PyExc_TypeError,
                    "Casting from StringDType to a structured dtype is not "
                    "supported.");
            // 返回错误码表示转换失败
            return (NPY_CASTING)-1;
        }
        // 增加给定描述符的引用计数,确保其在返回前不被销毁
        Py_INCREF(given_descrs[1]);
        // 将给定描述符复制到循环描述符数组的相应位置
        loop_descrs[1] = given_descrs[1];
    }

    // 增加给定描述符的引用计数,确保其在返回前不被销毁
    Py_INCREF(given_descrs[0]);
    // 将给定描述符复制到循环描述符数组的相应位置
    loop_descrs[0] = given_descrs[0];

    // 返回不安全转换的标志,表示允许不安全的类型转换
    return NPY_UNSAFE_CASTING;
}

static int
string_to_void(PyArrayMethod_Context *context, char *const data[],
               npy_intp const dimensions[], npy_intp const strides[],
               NpyAuxData *NPY_UNUSED(auxdata))
{
    // 获取输入描述符的字符串数据类型对象
    PyArray_StringDTypeObject *descr = (PyArray_StringDTypeObject *)context->descriptors[0];
    // 获取字符串分配器
    npy_string_allocator *allocator = NpyString_acquire_allocator(descr);
    // 检查是否有空值对象
    int has_null = descr->na_object != NULL;
    // 检查是否有字符串NA值
    int has_string_na = descr->has_string_na;
    // 获取默认字符串
    const npy_static_string *default_string = &descr->default_string;
    // 获取NA名称字符串
    const npy_static_string *na_name = &descr->na_name;
    // 获取第一维度的大小
    npy_intp N = dimensions[0];
    // 获取输入数据的指针
    char *in = data[0];
    // 获取输出数据的指针
    char *out = data[1];
    // 获取输入和输出数据的步幅
    npy_intp in_stride = strides[0];
    npy_intp out_stride = strides[1];
    // 获取输出数据的最大大小
    size_t max_out_size = context->descriptors[1]->elsize;

    // 遍历输入数据
    while (N--) {
        // 将输入数据解析为可空字符串
        const npy_packed_static_string *ps = (npy_packed_static_string *)in;
        npy_static_string s = {0, NULL};
        // 加载可空字符串,处理可能的截断或错误情况
        if (load_nullable_string(ps, &s, has_null, has_string_na,
                                 default_string, na_name, allocator,
                                 "in string to void cast") == -1) {
            // 加载失败,跳转到错误处理部分
            goto fail;
        }

        // 将字符串数据复制到输出位置,可能会截断UTF-8字符
        memcpy(out, s.buf, s.size > max_out_size ? max_out_size : s.size);
        // 如果实际字符串大小小于输出大小,用零填充剩余部分
        if (s.size < max_out_size) {
            memset(out + s.size, 0, (max_out_size - s.size));
        }

        // 更新输入和输出指针位置
        in += in_stride;
        out += out_stride;
    }

    // 释放字符串分配器
    NpyString_release_allocator(allocator);

    // 成功完成,返回0
    return 0;

fail:
    // 处理失败,释放字符串分配器并返回-1
    NpyString_release_allocator(allocator);
    return -1;
}

static PyType_Slot s2v_slots[] = {
    // 解析描述符的方法和函数指针
    {NPY_METH_resolve_descriptors, &string_to_void_resolve_descriptors},
    // 字符串到空值的函数指针
    {NPY_METH_strided_loop, &string_to_void},
    // 结束标记
    {0, NULL}
};

static char *s2v_name = "cast_StringDType_to_Void";

// 空值到字符串

static int
void_to_string(PyArrayMethod_Context *context, char *const data[],
               npy_intp const dimensions[], npy_intp const strides[],
               NpyAuxData *NPY_UNUSED(auxdata))
{
    // 获取描述符数组
    PyArray_Descr *const *descrs = context->descriptors;
    // 获取输出描述符的字符串数据类型对象
    PyArray_StringDTypeObject *descr = (PyArray_StringDTypeObject *)descrs[1];

    // 获取字符串分配器
    npy_string_allocator *allocator = NpyString_acquire_allocator(descr);

    // 获取输入描述符的最大大小
    long max_in_size = descrs[0]->elsize;

    // 获取第一维度的大小
    npy_intp N = dimensions[0];
    // 获取输入数据的指针(无符号字符指针)
    unsigned char *in = (unsigned char *)data[0];
    // 获取输出数据的指针
    char *out = data[1];

    // 获取输入和输出数据的步幅
    npy_intp in_stride = strides[0];
    npy_intp out_stride = strides[1];
    // 循环,执行 N 次,N 是循环控制变量
    while(N--) {
        // 计算输入数据的 UTF-8 编码后的字节数
        size_t out_num_bytes = utf8_buffer_size(in, max_in_size);
        // 如果计算出的字节数小于 0,表示发现无效的 UTF-8 字节序列,抛出错误并跳转到失败标签
        if (out_num_bytes < 0) {
            npy_gil_error(PyExc_TypeError,
                          "Invalid UTF-8 bytes found, cannot convert to UTF-8");
            goto fail;
        }
        // 定义一个静态字符串结构体 out_ss,并初始化为零
        npy_static_string out_ss = {0, NULL};
        // 调用 load_new_string 函数,将 out 转换为字符串,存储在 out_ss 中,使用 allocator 分配内存,描述为 "void to string cast"
        if (load_new_string((npy_packed_static_string *)out,
                            &out_ss, out_num_bytes, allocator,
                            "void to string cast") == -1) {
            // 如果 load_new_string 返回 -1,表示转换失败,跳转到失败标签
            goto fail;
        }
        // 将输入数据 in 复制到 out_buf 中,长度为 out_num_bytes
        char *out_buf = (char *)out_ss.buf;
        memcpy(out_buf, in, out_num_bytes);

        // 更新输入指针和输出指针的位置
        in += in_stride;
        out += out_stride;
    }

    // 释放 allocator 分配的内存资源
    NpyString_release_allocator(allocator);

    // 返回 0 表示成功
    return 0;
// 释放内存分配器
NpyString_release_allocator(allocator);

// 返回-1,表示函数执行失败
return -1;
}

// 定义 PyType_Slot 结构体数组 v2s_slots,用于描述一个 Python 类型的方法和数据
static PyType_Slot v2s_slots[] = {{NPY_METH_resolve_descriptors,
                                   &any_to_string_SAME_KIND_resolve_descriptors},
                                  {NPY_METH_strided_loop, &void_to_string},
                                  {0, NULL}};

// 字符串变为字节码

// static int 修饰符表明这是一个静态函数,只在当前文件可见
static int
string_to_bytes(PyArrayMethod_Context *context, char *const data[],
                npy_intp const dimensions[], npy_intp const strides[],
                NpyAuxData *NPY_UNUSED(auxdata))
{
    // 从上下文中获取字符串类型描述符
    PyArray_StringDTypeObject *descr = (PyArray_StringDTypeObject *)context->descriptors[0];
    // 获取字符串分配器
    npy_string_allocator *allocator = NpyString_acquire_allocator(descr);
    // 检查是否有空值对象
    int has_null = descr->na_object != NULL;
    // 检查是否有字符串 NA
    int has_string_na = descr->has_string_na;
    // 获取默认字符串
    const npy_static_string *default_string = &descr->default_string;
    // 获取 NA 名称
    const npy_static_string *na_name = &descr->na_name;
    // 获取第一个维度的大小
    npy_intp N = dimensions[0];
    // 获取输入数据的指针
    char *in = data[0];
    // 获取输出数据的指针
    char *out = data[1];
    // 获取输入数据的步幅
    npy_intp in_stride = strides[0];
    // 获取输出数据的步幅
    npy_intp out_stride = strides[1];
    // 获取输出数据的最大大小
    size_t max_out_size = context->descriptors[1]->elsize;

    // 迭代处理每一个输入字符串
    while (N--) {
        // 将输入数据解析为紧凑字符串结构体
        const npy_packed_static_string *ps = (npy_packed_static_string *)in;
        // 创建静态字符串结构体 s
        npy_static_string s = {0, NULL};
        // 加载可空字符串,如果加载失败则跳转到失败标签
        if (load_nullable_string(ps, &s, has_null, has_string_na,
                                 default_string, na_name, allocator,
                                 "in string to bytes cast") == -1) {
            goto fail;
        }

        // 检查字符串中是否有超过 127 的 ASCII 字符
        for (size_t i=0; i<s.size; i++) {
            if (((unsigned char *)s.buf)[i] > 127) {
                // 异常处理:ASCII 转换错误
                NPY_ALLOW_C_API_DEF;
                NPY_ALLOW_C_API;
                // 创建并设置 UnicodeEncodeError 异常对象
                PyObject *exc = PyObject_CallFunction(
                        PyExc_UnicodeEncodeError, "ss#nns", "ascii", s.buf,
                        (Py_ssize_t)s.size, (Py_ssize_t)i, (Py_ssize_t)(i+1), "ordinal not in range(128)");
                PyErr_SetObject(PyExceptionInstance_Class(exc), exc);
                Py_DECREF(exc);
                NPY_DISABLE_C_API;
                // 转换失败,跳转到失败标签
                goto fail;
            }
        }

        // 复制字符串数据到输出缓冲区,不超过最大输出大小
        memcpy(out, s.buf, s.size > max_out_size ? max_out_size : s.size);
        // 如果字符串大小小于最大输出大小,填充剩余空间
        if (s.size < max_out_size) {
            memset(out + s.size, 0, (max_out_size - s.size));
        }

        // 更新输入和输出指针
        in += in_stride;
        out += out_stride;
    }

    // 释放字符串分配器
    NpyString_release_allocator(allocator);

    // 返回成功
    return 0;

// 失败处理标签
fail:

    // 释放字符串分配器
    NpyString_release_allocator(allocator);

    // 返回 -1,表示函数执行失败
    return -1;
}

// 定义 PyType_Slot 结构体数组 s2bytes_slots,用于描述一个 Python 类型的方法和数据
static PyType_Slot s2bytes_slots[] = {
        {NPY_METH_resolve_descriptors, &string_to_fixed_width_resolve_descriptors},
        {NPY_METH_strided_loop, &string_to_bytes},
        {0, NULL}};

// 字节码变为字符串

// static int 修饰符表明这是一个静态函数,只在当前文件可见
static int
// 将字节转换为字符串的函数,使用给定的上下文、数据、维度、步长和辅助数据
static void bytes_to_string(PyArrayMethod_Context *context, char *const data[],
                            npy_intp const dimensions[], npy_intp const strides[],
                            NpyAuxData *NPY_UNUSED(auxdata))
{
    // 获取描述符数组
    PyArray_Descr *const *descrs = context->descriptors;
    // 获取第二个描述符作为字符串描述符
    PyArray_StringDTypeObject *descr = (PyArray_StringDTypeObject *)descrs[1];

    // 获取字符串分配器
    npy_string_allocator *allocator = NpyString_acquire_allocator(descr);

    // 获取最大输入大小
    size_t max_in_size = descrs[0]->elsize;

    // 获取第一个维度
    npy_intp N = dimensions[0];
    // 输入数据的无符号字符指针
    unsigned char *in = (unsigned char *)data[0];
    // 输出数据的字符指针
    char *out = data[1];

    // 输入和输出的步长
    npy_intp in_stride = strides[0];
    npy_intp out_stride = strides[1];

    // 循环处理每一个元素
    while(N--) {
        // 初始化输出字节数
        size_t out_num_bytes = max_in_size;

        // 忽略末尾的空字符
        while (out_num_bytes > 0 && in[out_num_bytes - 1] == 0) {
            out_num_bytes--;
        }

        // 定义静态字符串结构体
        npy_static_string out_ss = {0, NULL};
        // 调用加载新字符串的函数,将输入转换为输出静态字符串
        if (load_new_string((npy_packed_static_string *)out,
                            &out_ss, out_num_bytes, allocator,
                            "void to string cast") == -1) {
            // 失败时跳转到标签fail
            goto fail;
        }

        // 将输入复制到输出缓冲区
        char *out_buf = (char *)out_ss.buf;
        memcpy(out_buf, in, out_num_bytes);

        // 更新输入和输出指针
        in += in_stride;
        out += out_stride;
    }

    // 释放字符串分配器
    NpyString_release_allocator(allocator);

    return;

fail:
    // 失败时同样释放字符串分配器,并返回-1
    NpyString_release_allocator(allocator);

    return;
}

// 定义静态类型槽数组,用于描述类型转换的方法
static PyType_Slot bytes2s_slots[] = {
    // 解析描述符的方法和解析相同类型的字符串描述符的方法
    {NPY_METH_resolve_descriptors, &any_to_string_SAME_KIND_resolve_descriptors},
    // 使用字节转换为字符串的方法
    {NPY_METH_strided_loop, &bytes_to_string},
    // 空槽
    {0, NULL}
};

// 定义将字节转换为字符串的名称
static char *bytes2s_name = "cast_Bytes_to_StringDType";

// 返回描述类型转换的方法规范的函数
PyArrayMethod_Spec *
get_cast_spec(const char *name, NPY_CASTING casting,
              NPY_ARRAYMETHOD_FLAGS flags, PyArray_DTypeMeta **dtypes,
              PyType_Slot *slots)
{
    // 分配内存以存储方法规范
    PyArrayMethod_Spec *ret = PyMem_Malloc(sizeof(PyArrayMethod_Spec));

    // 设置方法规范的属性
    ret->name = name;
    ret->nin = 1;
    ret->nout = 1;
    ret->casting = casting;
    ret->flags = flags;
    ret->dtypes = dtypes;
    ret->slots = slots;

    return ret;
}

// 返回两个数据类型元信息的数组
PyArray_DTypeMeta **
get_dtypes(PyArray_DTypeMeta *dt1, PyArray_DTypeMeta *dt2)
{
    // 分配内存以存储两个数据类型元信息的数组
    PyArray_DTypeMeta **ret = PyMem_Malloc(2 * sizeof(PyArray_DTypeMeta *));

    // 设置数组的元素为输入的数据类型元信息
    ret[0] = dt1;
    ret[1] = dt2;

    return ret;
}

// 返回类型转换的方法规范的数组的函数
PyArrayMethod_Spec **
get_casts()
{
    // 使用字符串到字符串转换的名称
    char *t2t_name = s2s_name;

    // 获取字符串到字符串的数据类型元信息数组
    PyArray_DTypeMeta **t2t_dtypes =
            get_dtypes(&PyArray_StringDType,
                       &PyArray_StringDType);

    // 获取字符串到字符串的方法规范
    PyArrayMethod_Spec *ThisToThisCastSpec =
            get_cast_spec(t2t_name, NPY_UNSAFE_CASTING,
                          NPY_METH_SUPPORTS_UNALIGNED, t2t_dtypes, s2s_slots);

    // 初始类型转换的数量
    int num_casts = 43;

    // 根据字节大小添加类型转换数量
#if NPY_SIZEOF_BYTE == NPY_SIZEOF_SHORT
    num_casts += 4;
#endif
#if NPY_SIZEOF_SHORT == NPY_SIZEOF_INT
    num_casts += 4;
#endif
#if NPY_SIZEOF_INT == NPY_SIZEOF_LONG
    num_casts += 4;
#endif
#if NPY_SIZEOF_LONGLONG == NPY_SIZEOF_LONG
    num_casts += 4;
#endif
#endif

    // 获取 Unicode 到 String 的数据类型元信息数组
    PyArray_DTypeMeta **u2s_dtypes = get_dtypes(
            &PyArray_UnicodeDType, &PyArray_StringDType);

    // 获取 Unicode 到 String 类型转换方法的规范
    PyArrayMethod_Spec *UnicodeToStringCastSpec = get_cast_spec(
            u2s_name, NPY_SAME_KIND_CASTING, NPY_METH_NO_FLOATINGPOINT_ERRORS,
            u2s_dtypes, u2s_slots);

    // 获取 String 到 Unicode 的数据类型元信息数组
    PyArray_DTypeMeta **s2u_dtypes = get_dtypes(
            &PyArray_StringDType, &PyArray_UnicodeDType);

    // 获取 String 到 Unicode 类型转换方法的规范
    PyArrayMethod_Spec *StringToUnicodeCastSpec = get_cast_spec(
            s2u_name, NPY_SAME_KIND_CASTING, NPY_METH_NO_FLOATINGPOINT_ERRORS,
            s2u_dtypes, s2u_slots);

    // 获取 String 到 Bool 的数据类型元信息数组
    PyArray_DTypeMeta **s2b_dtypes =
            get_dtypes(&PyArray_StringDType, &PyArray_BoolDType);

    // 获取 String 到 Bool 类型转换方法的规范
    PyArrayMethod_Spec *StringToBoolCastSpec = get_cast_spec(
            s2b_name, NPY_SAME_KIND_CASTING, NPY_METH_NO_FLOATINGPOINT_ERRORS,
            s2b_dtypes, s2b_slots);

    // 获取 Bool 到 String 的数据类型元信息数组
    PyArray_DTypeMeta **b2s_dtypes =
            get_dtypes(&PyArray_BoolDType, &PyArray_StringDType);

    // 获取 Bool 到 String 类型转换方法的规范
    PyArrayMethod_Spec *BoolToStringCastSpec = get_cast_spec(
            b2s_name, NPY_SAME_KIND_CASTING, NPY_METH_NO_FLOATINGPOINT_ERRORS,
            b2s_dtypes, b2s_slots);

    // 定义各个整数类型到相应的类型转换规范
    DTYPES_AND_CAST_SPEC(i8, Int8)
    DTYPES_AND_CAST_SPEC(i16, Int16)
    DTYPES_AND_CAST_SPEC(i32, Int32)
    DTYPES_AND_CAST_SPEC(i64, Int64)
    DTYPES_AND_CAST_SPEC(u8, UInt8)
    DTYPES_AND_CAST_SPEC(u16, UInt16)
    DTYPES_AND_CAST_SPEC(u32, UInt32)
    DTYPES_AND_CAST_SPEC(u64, UInt64)
#if NPY_SIZEOF_BYTE == NPY_SIZEOF_SHORT
    DTYPES_AND_CAST_SPEC(byte, Byte)
    DTYPES_AND_CAST_SPEC(ubyte, UByte)
#endif
#if NPY_SIZEOF_SHORT == NPY_SIZEOF_INT
    DTYPES_AND_CAST_SPEC(short, Short)
    DTYPES_AND_CAST_SPEC(ushort, UShort)
#endif
#if NPY_SIZEOF_INT == NPY_SIZEOF_LONG
    DTYPES_AND_CAST_SPEC(int, Int)
    DTYPES_AND_CAST_SPEC(uint, UInt)
#endif
#if NPY_SIZEOF_LONGLONG == NPY_SIZEOF_LONG
    DTYPES_AND_CAST_SPEC(longlong, LongLong)
    DTYPES_AND_CAST_SPEC(ulonglong, ULongLong)
#endif

    // 定义各个浮点数类型到相应的类型转换规范
    DTYPES_AND_CAST_SPEC(f64, Double)
    DTYPES_AND_CAST_SPEC(f32, Float)
    DTYPES_AND_CAST_SPEC(f16, Half)

    // 获取 String 到 Datetime 的数据类型元信息数组
    PyArray_DTypeMeta **s2dt_dtypes = get_dtypes(
            &PyArray_StringDType, &PyArray_DatetimeDType);

    // 获取 String 到 Datetime 类型转换方法的规范
    PyArrayMethod_Spec *StringToDatetimeCastSpec = get_cast_spec(
            s2dt_name, NPY_UNSAFE_CASTING,
            NPY_METH_NO_FLOATINGPOINT_ERRORS | NPY_METH_REQUIRES_PYAPI,
            s2dt_dtypes, s2dt_slots);

    // 获取 Datetime 到 String 的数据类型元信息数组
    PyArray_DTypeMeta **dt2s_dtypes = get_dtypes(
            &PyArray_DatetimeDType, &PyArray_StringDType);

    // 获取 Datetime 到 String 类型转换方法的规范
    PyArrayMethod_Spec *DatetimeToStringCastSpec = get_cast_spec(
            dt2s_name, NPY_SAFE_CASTING,
            NPY_METH_NO_FLOATINGPOINT_ERRORS | NPY_METH_REQUIRES_PYAPI,
            dt2s_dtypes, dt2s_slots);

    // 获取 String 到 Timedelta 的数据类型元信息数组
    PyArray_DTypeMeta **s2td_dtypes = get_dtypes(
            &PyArray_StringDType, &PyArray_TimedeltaDType);
    // 创建 StringToTimedeltaCastSpec 变量,并使用 get_cast_spec 函数获取字符串到时间增量的转换规格
    PyArrayMethod_Spec *StringToTimedeltaCastSpec = get_cast_spec(
            s2td_name, NPY_UNSAFE_CASTING,
            NPY_METH_NO_FLOATINGPOINT_ERRORS | NPY_METH_REQUIRES_PYAPI,
            s2td_dtypes, s2td_slots);

    // 使用 get_dtypes 函数获取 PyArray_TimedeltaDType 和 PyArray_StringDType 的数据类型元信息,存储在 td2s_dtypes 中
    PyArray_DTypeMeta **td2s_dtypes = get_dtypes(
            &PyArray_TimedeltaDType, &PyArray_StringDType);

    // 创建 TimedeltaToStringCastSpec 变量,并使用 get_cast_spec 函数获取时间增量到字符串的转换规格
    PyArrayMethod_Spec *TimedeltaToStringCastSpec = get_cast_spec(
            td2s_name, NPY_SAFE_CASTING,
            NPY_METH_NO_FLOATINGPOINT_ERRORS | NPY_METH_REQUIRES_PYAPI,
            td2s_dtypes, td2s_slots);

    // 使用 get_dtypes 函数获取 PyArray_StringDType 和 PyArray_LongDoubleDType 的数据类型元信息,存储在 s2ld_dtypes 中
    PyArray_DTypeMeta **s2ld_dtypes = get_dtypes(
            &PyArray_StringDType, &PyArray_LongDoubleDType);

    // 创建 StringToLongDoubleCastSpec 变量,并使用 get_cast_spec 函数获取字符串到长双精度浮点数的转换规格
    PyArrayMethod_Spec *StringToLongDoubleCastSpec = get_cast_spec(
            s2ld_name, NPY_UNSAFE_CASTING, NPY_METH_NO_FLOATINGPOINT_ERRORS,
            s2ld_dtypes, s2ld_slots);

    // 使用 get_dtypes 函数获取 PyArray_LongDoubleDType 和 PyArray_StringDType 的数据类型元信息,存储在 ld2s_dtypes 中
    PyArray_DTypeMeta **ld2s_dtypes = get_dtypes(
            &PyArray_LongDoubleDType, &PyArray_StringDType);

    // 创建 LongDoubleToStringCastSpec 变量,并使用 get_cast_spec 函数获取长双精度浮点数到字符串的转换规格
    PyArrayMethod_Spec *LongDoubleToStringCastSpec = get_cast_spec(
            ld2s_name, NPY_SAFE_CASTING,
            NPY_METH_NO_FLOATINGPOINT_ERRORS | NPY_METH_REQUIRES_PYAPI,
            ld2s_dtypes, ld2s_slots);

    // 调用宏 DTYPES_AND_CAST_SPEC 生成有关复数浮点数到浮点数的转换规格代码
    DTYPES_AND_CAST_SPEC(cfloat, CFloat)
    DTYPES_AND_CAST_SPEC(cdouble, CDouble)
    DTYPES_AND_CAST_SPEC(clongdouble, CLongDouble)

    // 使用 get_dtypes 函数获取 PyArray_StringDType 和 PyArray_VoidDType 的数据类型元信息,存储在 s2v_dtypes 中
    PyArray_DTypeMeta **s2v_dtypes = get_dtypes(
            &PyArray_StringDType, &PyArray_VoidDType);

    // 创建 StringToVoidCastSpec 变量,并使用 get_cast_spec 函数获取字符串到 void 类型的转换规格
    PyArrayMethod_Spec *StringToVoidCastSpec = get_cast_spec(
            s2v_name, NPY_SAME_KIND_CASTING, NPY_METH_NO_FLOATINGPOINT_ERRORS,
            s2v_dtypes, s2v_slots);

    // 使用 get_dtypes 函数获取 PyArray_VoidDType 和 PyArray_StringDType 的数据类型元信息,存储在 v2s_dtypes 中
    PyArray_DTypeMeta **v2s_dtypes = get_dtypes(
            &PyArray_VoidDType, &PyArray_StringDType);

    // 创建 VoidToStringCastSpec 变量,并使用 get_cast_spec 函数获取 void 类型到字符串的转换规格
    PyArrayMethod_Spec *VoidToStringCastSpec = get_cast_spec(
            v2s_name, NPY_SAME_KIND_CASTING, NPY_METH_NO_FLOATINGPOINT_ERRORS,
            v2s_dtypes, v2s_slots);

    // 使用 get_dtypes 函数获取 PyArray_StringDType 和 PyArray_BytesDType 的数据类型元信息,存储在 s2bytes_dtypes 中
    PyArray_DTypeMeta **s2bytes_dtypes = get_dtypes(
            &PyArray_StringDType, &PyArray_BytesDType);

    // 创建 StringToBytesCastSpec 变量,并使用 get_cast_spec 函数获取字符串到字节流的转换规格
    PyArrayMethod_Spec *StringToBytesCastSpec = get_cast_spec(
            s2bytes_name, NPY_SAME_KIND_CASTING, NPY_METH_NO_FLOATINGPOINT_ERRORS,
            s2bytes_dtypes, s2bytes_slots);

    // 使用 get_dtypes 函数获取 PyArray_BytesDType 和 PyArray_StringDType 的数据类型元信息,存储在 bytes2s_dtypes 中
    PyArray_DTypeMeta **bytes2s_dtypes = get_dtypes(
            &PyArray_BytesDType, &PyArray_StringDType);

    // 创建 BytesToStringCastSpec 变量,并使用 get_cast_spec 函数获取字节流到字符串的转换规格
    PyArrayMethod_Spec *BytesToStringCastSpec = get_cast_spec(
            bytes2s_name, NPY_SAME_KIND_CASTING, NPY_METH_NO_FLOATINGPOINT_ERRORS,
            bytes2s_dtypes, bytes2s_slots);

    // 分配内存以存储所有转换规格的数组,并将指针存储在 casts 中
    PyArrayMethod_Spec **casts =
            PyMem_Malloc((num_casts + 1) * sizeof(PyArrayMethod_Spec *));

    // 初始化计数器 cast_i
    int cast_i = 0;

    // 将各种转换规格添加到 casts 数组中
    casts[cast_i++] = ThisToThisCastSpec;
    casts[cast_i++] = UnicodeToStringCastSpec;
    casts[cast_i++] = StringToUnicodeCastSpec;
    casts[cast_i++] = StringToBoolCastSpec;
    casts[cast_i++] = BoolToStringCastSpec;
    casts[cast_i++] = StringToInt8CastSpec;
    casts[cast_i++] = Int8ToStringCastSpec;
    casts[cast_i++] = StringToInt16CastSpec;
    # 将 Int16ToStringCastSpec 转换函数添加到 casts 数组中,cast_i 自增
    casts[cast_i++] = Int16ToStringCastSpec;
    # 将 StringToInt32CastSpec 转换函数添加到 casts 数组中,cast_i 自增
    casts[cast_i++] = StringToInt32CastSpec;
    # 将 Int32ToStringCastSpec 转换函数添加到 casts 数组中,cast_i 自增
    casts[cast_i++] = Int32ToStringCastSpec;
    # 将 StringToInt64CastSpec 转换函数添加到 casts 数组中,cast_i 自增
    casts[cast_i++] = StringToInt64CastSpec;
    # 将 Int64ToStringCastSpec 转换函数添加到 casts 数组中,cast_i 自增
    casts[cast_i++] = Int64ToStringCastSpec;
    # 将 StringToUInt8CastSpec 转换函数添加到 casts 数组中,cast_i 自增
    casts[cast_i++] = StringToUInt8CastSpec;
    # 将 UInt8ToStringCastSpec 转换函数添加到 casts 数组中,cast_i 自增
    casts[cast_i++] = UInt8ToStringCastSpec;
    # 将 StringToUInt16CastSpec 转换函数添加到 casts 数组中,cast_i 自增
    casts[cast_i++] = StringToUInt16CastSpec;
    # 将 UInt16ToStringCastSpec 转换函数添加到 casts 数组中,cast_i 自增
    casts[cast_i++] = UInt16ToStringCastSpec;
    # 将 StringToUInt32CastSpec 转换函数添加到 casts 数组中,cast_i 自增
    casts[cast_i++] = StringToUInt32CastSpec;
    # 将 UInt32ToStringCastSpec 转换函数添加到 casts 数组中,cast_i 自增
    casts[cast_i++] = UInt32ToStringCastSpec;
    # 将 StringToUInt64CastSpec 转换函数添加到 casts 数组中,cast_i 自增
    casts[cast_i++] = StringToUInt64CastSpec;
    # 将 UInt64ToStringCastSpec 转换函数添加到 casts 数组中,cast_i 自增
    casts[cast_i++] = UInt64ToStringCastSpec;
#if NPY_SIZEOF_BYTE == NPY_SIZEOF_SHORT
    // 如果字节大小等于短整型大小,添加字节到短整型的类型转换函数到 casts 数组中
    casts[cast_i++] = StringToByteCastSpec;
    casts[cast_i++] = ByteToStringCastSpec;
    casts[cast_i++] = StringToUByteCastSpec;
    casts[cast_i++] = UByteToStringCastSpec;
#endif

#if NPY_SIZEOF_SHORT == NPY_SIZEOF_INT
    // 如果短整型大小等于整型大小,添加短整型到整型的类型转换函数到 casts 数组中
    casts[cast_i++] = StringToShortCastSpec;
    casts[cast_i++] = ShortToStringCastSpec;
    casts[cast_i++] = StringToUShortCastSpec;
    casts[cast_i++] = UShortToStringCastSpec;
#endif

#if NPY_SIZEOF_INT == NPY_SIZEOF_LONG
    // 如果整型大小等于长整型大小,添加整型到长整型的类型转换函数到 casts 数组中
    casts[cast_i++] = StringToIntCastSpec;
    casts[cast_i++] = IntToStringCastSpec;
    casts[cast_i++] = StringToUIntCastSpec;
    casts[cast_i++] = UIntToStringCastSpec;
#endif

#if NPY_SIZEOF_LONGLONG == NPY_SIZEOF_LONG
    // 如果长长整型大小等于长整型大小,添加长长整型到长整型的类型转换函数到 casts 数组中
    casts[cast_i++] = StringToLongLongCastSpec;
    casts[cast_i++] = LongLongToStringCastSpec;
    casts[cast_i++] = StringToULongLongCastSpec;
    casts[cast_i++] = ULongLongToStringCastSpec;
#endif

// 添加字符串到双精度浮点数的类型转换函数到 casts 数组中
casts[cast_i++] = StringToDoubleCastSpec;
casts[cast_i++] = DoubleToStringCastSpec;
// 添加字符串到单精度浮点数的类型转换函数到 casts 数组中
casts[cast_i++] = StringToFloatCastSpec;
casts[cast_i++] = FloatToStringCastSpec;
// 添加字符串到半精度浮点数的类型转换函数到 casts 数组中
casts[cast_i++] = StringToHalfCastSpec;
casts[cast_i++] = HalfToStringCastSpec;
// 添加字符串到日期时间的类型转换函数到 casts 数组中
casts[cast_i++] = StringToDatetimeCastSpec;
casts[cast_i++] = DatetimeToStringCastSpec;
// 添加字符串到时间增量的类型转换函数到 casts 数组中
casts[cast_i++] = StringToTimedeltaCastSpec;
casts[cast_i++] = TimedeltaToStringCastSpec;
// 添加字符串到长双精度浮点数的类型转换函数到 casts 数组中
casts[cast_i++] = StringToLongDoubleCastSpec;
casts[cast_i++] = LongDoubleToStringCastSpec;
// 添加字符串到复数单精度浮点数的类型转换函数到 casts 数组中
casts[cast_i++] = StringToCFloatCastSpec;
casts[cast_i++] = CFloatToStringCastSpec;
// 添加字符串到复数双精度浮点数的类型转换函数到 casts 数组中
casts[cast_i++] = StringToCDoubleCastSpec;
casts[cast_i++] = CDoubleToStringCastSpec;
// 添加字符串到复数长双精度浮点数的类型转换函数到 casts 数组中
casts[cast_i++] = StringToCLongDoubleCastSpec;
casts[cast_i++] = CLongDoubleToStringCastSpec;
// 添加字符串到无类型的类型转换函数到 casts 数组中
casts[cast_i++] = StringToVoidCastSpec;
casts[cast_i++] = VoidToStringCastSpec;
// 添加字符串到字节串的类型转换函数到 casts 数组中
casts[cast_i++] = StringToBytesCastSpec;
casts[cast_i++] = BytesToStringCastSpec;
// 将 NULL 添加到 casts 数组末尾作为结束标志
casts[cast_i++] = NULL;

// 断言最后一个元素为 NULL,确保 casts 数组以 NULL 结束
assert(casts[num_casts] == NULL);
// 断言 cast_i 的值为 num_casts + 1,确保 casts 数组中元素的数量正确
assert(cast_i == num_casts + 1);

// 返回填充完毕的 casts 数组
return casts;
}

.\numpy\numpy\_core\src\multiarray\stringdtype\casts.h

#ifndef _NPY_CORE_SRC_MULTIARRAY_STRINGDTYPE_CASTS_H_
// 如果 _NPY_CORE_SRC_MULTIARRAY_STRINGDTYPE_CASTS_H_ 宏未定义,则执行以下操作
#define _NPY_CORE_SRC_MULTIARRAY_STRINGDTYPE_CASTS_H_
// 定义 _NPY_CORE_SRC_MULTIARRAY_STRINGDTYPE_CASTS_H_ 宏,防止重复包含

// 声明一个指向 PyArrayMethod_Spec* 类型指针数组的函数 get_casts()
PyArrayMethod_Spec **
get_casts();

// 结束条件,关闭 ifndef 宏保护区域
#endif /* _NPY_CORE_SRC_MULTIARRAY_STRINGDTYPE_CASTS_H_ */
// 结束宏定义的注释

.\numpy\numpy\_core\src\multiarray\stringdtype\dtype.c

/* StringDType 类的实现 */
#define PY_SSIZE_T_CLEAN  // 清除 Python 中使用的 ssize_t 的宏定义
#include <Python.h>       // Python C API 的主头文件
#include "structmember.h" // Python 结构成员访问的辅助宏

#define NPY_NO_DEPRECATED_API NPY_API_VERSION  // 使用最新的 NumPy API 版本
#define _MULTIARRAYMODULE  // 多维数组模块标识符

#include "numpy/arrayobject.h"    // NumPy 数组对象的头文件
#include "numpy/ndarraytypes.h"   // NumPy 数组类型的头文件
#include "numpy/npy_math.h"       // NumPy 中的数学函数
#include "static_string.h"        // 静态字符串实用工具
#include "dtypemeta.h"            // 数据类型元信息
#include "dtype.h"                // 数据类型定义
#include "casts.h"                // 类型转换函数
#include "gil_utils.h"            // 全局解释器锁 (GIL) 工具函数
#include "conversion_utils.h"     // 类型转换实用工具
#include "npy_import.h"           // NumPy 导入实用工具
#include "multiarraymodule.h"     // 多维数组模块核心

/*
 * 内部辅助函数,用于创建新实例
 */
PyObject *
new_stringdtype_instance(PyObject *na_object, int coerce)
{
    PyObject *new =
            PyArrayDescr_Type.tp_new((PyTypeObject *)&PyArray_StringDType, NULL, NULL); // 创建新的 PyArrayDescr_Type 实例

    if (new == NULL) {
        return NULL;  // 如果创建失败,返回空指针
    }

    char *default_string_buf = NULL;  // 默认字符串缓冲区
    char *na_name_buf = NULL;          // NA 名称缓冲区

    npy_string_allocator *allocator = NpyString_new_allocator(PyMem_RawMalloc, PyMem_RawFree,
                                                              PyMem_RawRealloc);  // 创建字符串分配器

    if (allocator == NULL) {
        PyErr_SetString(PyExc_MemoryError,
                        "Failed to create string allocator");  // 如果分配器创建失败,设置内存错误并跳转到 fail 标签
        goto fail;
    }

    npy_static_string default_string = {0, NULL};  // 默认静态字符串结构体
    npy_static_string na_name = {0, NULL};         // NA 名称静态字符串结构体

    Py_XINCREF(na_object);  // 增加 NA 对象的引用计数
    ((PyArray_StringDTypeObject *)new)->na_object = na_object;  // 设置新实例的 NA 对象指针
    int has_null = na_object != NULL;  // 是否具有 NULL 值
    int has_nan_na = 0;  // 是否具有 NaN 或 NA 值
    int has_string_na = 0;  // 是否具有字符串类型的 NA 值
    if (has_null) {
        // 如果存在缺失值标记

        // 首先检查是否为字符串类型
        if (PyUnicode_Check(na_object)) {
            // 如果是 Python 字符串对象
            has_string_na = 1;
            // 获取字符串对象的 UTF-8 编码及其大小
            Py_ssize_t size = 0;
            const char *buf = PyUnicode_AsUTF8AndSize(na_object, &size);
            if (buf == NULL) {
                goto fail;
            }
            // 分配内存并拷贝字符串数据
            default_string.buf = PyMem_RawMalloc(size);
            if (default_string.buf == NULL) {
                PyErr_NoMemory();
                goto fail;
            }
            memcpy((char *)default_string.buf, buf, size);
            default_string.size = size;
        }
        else {
            // 若非字符串对象,则视为类 NaN 的对象
            PyObject *ne_result = PyObject_RichCompare(na_object, na_object, Py_NE);
            if (ne_result == NULL) {
                goto fail;
            }
            // 检查比较结果是否真值
            int is_truthy = PyObject_IsTrue(ne_result);
            if (is_truthy == -1) {
                PyErr_Clear();
                has_nan_na = 1;
            }
            else if (is_truthy == 1) {
                has_nan_na = 1;
            }
            Py_DECREF(ne_result);
        }

        // 转换缺失值对象为字符串
        PyObject *na_pystr = PyObject_Str(na_object);
        if (na_pystr == NULL) {
            goto fail;
        }

        // 获取字符串对象的 UTF-8 编码及其大小
        Py_ssize_t size = 0;
        const char *utf8_ptr = PyUnicode_AsUTF8AndSize(na_pystr, &size);
        if (utf8_ptr == NULL) {
            Py_DECREF(na_pystr);
            goto fail;
        }
        // 分配内存并拷贝字符串数据
        na_name.buf = PyMem_RawMalloc(size);
        if (na_name.buf == NULL) {
            Py_DECREF(na_pystr);
            goto fail;
        }
        memcpy((char *)na_name.buf, utf8_ptr, size);
        na_name.size = size;
        Py_DECREF(na_pystr);
    }

    // 转换为 PyArray_StringDTypeObject 类型的指针
    PyArray_StringDTypeObject *snew = (PyArray_StringDTypeObject *)new;

    // 设置结构体成员变量值
    snew->has_nan_na = has_nan_na;
    snew->has_string_na = has_string_na;
    snew->coerce = coerce;
    snew->allocator = allocator;
    snew->array_owned = 0;
    snew->na_name = na_name;
    snew->default_string = default_string;

    // 转换为 PyArray_Descr 类型的指针
    PyArray_Descr *base = (PyArray_Descr *)new;
    // 设置描述符的大小和对齐方式
    base->elsize = SIZEOF_NPY_PACKED_STATIC_STRING;
    base->alignment = ALIGNOF_NPY_PACKED_STATIC_STRING;
    // 设置标志位
    base->flags |= NPY_NEEDS_INIT;
    base->flags |= NPY_LIST_PICKLE;
    base->flags |= NPY_ITEM_REFCOUNT;
    // 设置数据类型编号和类型标识
    base->type_num = NPY_VSTRING;
    base->kind = NPY_VSTRINGLTR;
    base->type = NPY_VSTRINGLTR;

    // 返回新创建的描述符对象
    return new;
fail:
    // 减少 new 对象的引用计数,因为返回 NULL 意味着无法返回新对象
    Py_DECREF(new);
    // 检查并释放默认字符串缓冲区
    if (default_string_buf != NULL) {
        PyMem_RawFree(default_string_buf);
    }
    // 检查并释放 na_name_buf 字符串缓冲区
    if (na_name_buf != NULL) {
        PyMem_RawFree(na_name_buf);
    }
    // 检查并释放分配器
    if (allocator != NULL) {
        NpyString_free_allocator(allocator);
    }
    // 返回 NULL 指示出错
    return NULL;
}

static int
na_eq_cmp(PyObject *a, PyObject *b) {
    // 检查对象是否完全相同,包括 None 和 Pandas.NA 这样的单例对象
    if (a == b) {
        return 1;
    }
    // 如果其中一个对象为 NULL,则返回不相等
    if (a == NULL || b == NULL) {
        return 0;
    }
    // 如果两个对象都是浮点数对象,则进行 NaN 检查
    if (PyFloat_Check(a) && PyFloat_Check(b)) {
        // 获取浮点数值并检查是否为 NaN
        double a_float = PyFloat_AsDouble(a);
        if (a_float == -1.0 && PyErr_Occurred()) {
            return -1;  // 出错时返回 -1
        }
        double b_float = PyFloat_AsDouble(b);
        if (b_float == -1.0 && PyErr_Occurred()) {
            return -1;  // 出错时返回 -1
        }
        // 如果两者均为 NaN,则视为相等
        if (npy_isnan(a_float) && npy_isnan(b_float)) {
            return 1;
        }
    }
    // 使用 PyObject_RichCompareBool 函数比较对象是否相等
    int ret = PyObject_RichCompareBool(a, b, Py_EQ);
    if (ret == -1) {
        PyErr_Clear();  // 清除异常状态
        return 0;
    }
    return ret;
}

// 设置确定 dtype 实例间相等性的逻辑规则
int
_eq_comparison(int scoerce, int ocoerce, PyObject *sna, PyObject *ona)
{
    // 如果 scoerce 与 ocoerce 不相等,则返回不相等
    if (scoerce != ocoerce) {
        return 0;
    }
    // 调用 na_eq_cmp 函数比较 sna 和 ona 对象是否相等
    return na_eq_cmp(sna, ona);
}

// 当处理不同 dtype 的混合时,用于确定返回的正确 dtype 实例
NPY_NO_EXPORT int
stringdtype_compatible_na(PyObject *na1, PyObject *na2, PyObject **out_na) {
    // 如果 na1 和 na2 都不为空,则比较它们是否相等
    if ((na1 != NULL) && (na2 != NULL)) {
        int na_eq = na_eq_cmp(na1, na2);

        // 如果比较出错,返回 -1
        if (na_eq < 0) {
            return -1;
        }
        // 如果 na1 和 na2 不相等,抛出类型错误异常
        else if (na_eq == 0) {
            PyErr_Format(PyExc_TypeError,
                         "Cannot find a compatible null string value for "
                         "null strings '%R' and '%R'", na1, na2);
            return -1;
        }
    }
    // 如果 out_na 不为空,则将 na1 或 na2 赋给 *out_na
    if (out_na != NULL) {
        *out_na = na1 ? na1 : na2;
    }
    return 0;
}

/*
 * 用于确定处理不同 dtype(例如从标量列表创建数组时)时返回的正确 dtype 实例
 */
static PyArray_StringDTypeObject *
common_instance(PyArray_StringDTypeObject *dtype1, PyArray_StringDTypeObject *dtype2)
{
    PyObject *out_na_object = NULL;

    // 检查 na1 和 na2 是否兼容,如果不兼容,返回 NULL,并抛出类型错误异常
    if (stringdtype_compatible_na(
                dtype1->na_object, dtype2->na_object, &out_na_object) == -1) {
        PyErr_Format(PyExc_TypeError,
                     "Cannot find common instance for incompatible dtypes "
                     "'%R' and '%R'", (PyObject *)dtype1, (PyObject *)dtype2);
        return NULL;
    }

    // 返回新的 string dtype 实例,基于 out_na_object 和 dtype1 是否强制转换的条件
    return (PyArray_StringDTypeObject *)new_stringdtype_instance(
            out_na_object, dtype1->coerce && dtype1->coerce);
}
/*
 *  用于确定用于数据类型提升的正确“常见”数据类型。
 *  cls 总是 PyArray_StringDType,other 是任意其他数据类型。
 */
static PyArray_DTypeMeta *
common_dtype(PyArray_DTypeMeta *cls, PyArray_DTypeMeta *other)
{
    // 如果 other 的类型码是 NPY_UNICODE
    if (other->type_num == NPY_UNICODE) {
        /*
         *  我们需要从 unicode 进行类型转换,因此允许 unicode 转换为 PyArray_StringDType
         */
        Py_INCREF(cls);  // 增加 cls 的引用计数
        return cls;      // 返回 cls
    }
    Py_INCREF(Py_NotImplemented);  // 增加 Py_NotImplemented 的引用计数
    return (PyArray_DTypeMeta *)Py_NotImplemented;  // 返回 Py_NotImplemented
}

/*
 * 返回一个对 `scalar` 的字符串表示的新引用。
 * 如果 scalar 不是字符串且 coerce 非零,则调用 __str__ 将其转换为字符串。
 * 如果 coerce 为零,则对非字符串或非 NA 输入引发错误。
 */
static PyObject *
as_pystring(PyObject *scalar, int coerce)
{
    PyTypeObject *scalar_type = Py_TYPE(scalar);  // 获取 scalar 的类型对象

    // 如果 scalar 的类型是 PyUnicode_Type
    if (scalar_type == &PyUnicode_Type) {
        Py_INCREF(scalar);  // 增加 scalar 的引用计数
        return scalar;      // 返回 scalar
    }

    // 如果 coerce 为零
    if (coerce == 0) {
        PyErr_SetString(PyExc_ValueError,
                        "StringDType 只允许在禁用字符串强制转换时使用字符串数据。");
        return NULL;  // 返回 NULL,表示出错
    }
    else {
        // 尝试将 scalar 转换为字符串
        scalar = PyObject_Str(scalar);
        if (scalar == NULL) {
            // 如果 PyObject_Str 调用失败,返回 NULL
            return NULL;
        }
    }
    return scalar;  // 返回 scalar
}

/*
 * 从 Python 对象 `obj` 中发现描述符,并返回 PyArray_Descr 对象。
 */
static PyArray_Descr *
string_discover_descriptor_from_pyobject(PyTypeObject *NPY_UNUSED(cls),
                                         PyObject *obj)
{
    PyObject *val = as_pystring(obj, 1);  // 获取 obj 的字符串表示
    if (val == NULL) {
        return NULL;  // 如果获取失败,返回 NULL
    }

    Py_DECREF(val);  // 释放 val 的引用计数

    // 创建一个新的字符串数据类型描述符实例并返回
    PyArray_Descr *ret = (PyArray_Descr *)new_stringdtype_instance(NULL, 1);

    return ret;  // 返回描述符实例
}

/*
 * 将 Python 对象 `obj` 插入到数据类型为 `descr` 的数组中,在 dataptr 给定的位置。
 */
int
stringdtype_setitem(PyArray_StringDTypeObject *descr, PyObject *obj, char **dataptr)
{
    npy_packed_static_string *sdata = (npy_packed_static_string *)dataptr;

    // 借用引用
    PyObject *na_object = descr->na_object;

    // 在获取分配器后需要比较结果,但在获取分配器时不能使用需要 GIL 的函数,因此在获取分配器前进行比较。

    // 执行 na_eq_cmp 比较
    int na_cmp = na_eq_cmp(obj, na_object);
    if (na_cmp == -1) {
        return -1;  // 如果比较失败,返回 -1
    }

    // 获取字符串分配器
    npy_string_allocator *allocator = NpyString_acquire_allocator(descr);

    // 如果 na_object 不为 NULL
    if (na_object != NULL) {
        if (na_cmp) {
            // 如果比较结果为真,尝试将空值打包到 sdata 中
            if (NpyString_pack_null(allocator, sdata) < 0) {
                PyErr_SetString(PyExc_MemoryError,
                                "Failed to pack null string during StringDType "
                                "setitem");
                goto fail;  // 打包失败,跳转到 fail 标签处处理错误
            }
            goto success;  // 成功处理
        }
    }

    // 将 obj 转换为字符串,并根据 descr->coerce 的值进行处理
    PyObject *val_obj = as_pystring(obj, descr->coerce);
    # 如果 val_obj 为 NULL,则跳转到失败处理的标签
    if (val_obj == NULL) {
        goto fail;
    }

    # 初始化长度变量为 0
    Py_ssize_t length = 0;
    # 将 val_obj 转换为 UTF-8 编码的字符串,并获取其长度
    const char *val = PyUnicode_AsUTF8AndSize(val_obj, &length);
    # 如果转换失败(val 为 NULL),释放 val_obj 并跳转到失败处理的标签
    if (val == NULL) {
        Py_DECREF(val_obj);
        goto fail;
    }

    # 使用 NpyString_pack 函数将字符串数据 val 打包到 sdata 中,
    # 如果返回值小于 0,表示打包过程出错,设置内存错误异常信息,
    # 释放 val_obj 并跳转到失败处理的标签
    if (NpyString_pack(allocator, sdata, val, length) < 0) {
        PyErr_SetString(PyExc_MemoryError,
                        "Failed to pack string during StringDType "
                        "setitem");
        Py_DECREF(val_obj);
        goto fail;
    }
    # 打包成功后,释放 val_obj
    Py_DECREF(val_obj);
// 释放分配给 NpyString 的内存空间
NpyString_release_allocator(allocator);

// 返回成功标志
return 0;

fail:
    // 释放分配给 NpyString 的内存空间
    NpyString_release_allocator(allocator);

    // 返回失败标志
    return -1;
}

static PyObject *
stringdtype_getitem(PyArray_StringDTypeObject *descr, char **dataptr)
{
    // 初始化变量
    PyObject *val_obj = NULL;
    npy_packed_static_string *psdata = (npy_packed_static_string *)dataptr;
    npy_static_string sdata = {0, NULL};
    int has_null = descr->na_object != NULL;
    // 获取字符串分配器
    npy_string_allocator *allocator = NpyString_acquire_allocator(descr);
    // 加载字符串数据
    int is_null = NpyString_load(allocator, psdata, &sdata);

    // 处理加载过程中的错误
    if (is_null < 0) {
        PyErr_SetString(PyExc_MemoryError,
                        "Failed to load string in StringDType getitem");
        // 转到失败处理标签
        goto fail;
    }
    else if (is_null == 1) {
        // 处理字符串为空的情况
        if (has_null) {
            // 返回NA对象
            PyObject *na_object = descr->na_object;
            Py_INCREF(na_object);
            val_obj = na_object;
        }
        else {
            // 返回空字符串对象
            val_obj = PyUnicode_FromStringAndSize("", 0);
        }
    }
    else {
        // 处理字符串不为空的情况
#ifndef PYPY_VERSION
        val_obj = PyUnicode_FromStringAndSize(sdata.buf, sdata.size);
#else
        // PyPy 版本兼容性处理
        val_obj = PyUnicode_FromStringAndSize(
                sdata.buf == NULL ? "" : sdata.buf, sdata.size);
#endif
        // 检查对象是否成功创建
        if (val_obj == NULL) {
            // 转到失败处理标签
            goto fail;
        }
    }

    // 释放分配给 NpyString 的内存空间
    NpyString_release_allocator(allocator);

    // 返回创建的对象
    return val_obj;

fail:
    // 处理失败情况下的资源释放
    NpyString_release_allocator(allocator);

    // 返回空对象
    return NULL;
}

// PyArray_NonzeroFunc
// Unicode 字符串长度非零时返回真值。
npy_bool
nonzero(void *data, void *arr)
{
    // 获取描述器
    PyArray_StringDTypeObject *descr = (PyArray_StringDTypeObject *)PyArray_DESCR(arr);
    int has_null = descr->na_object != NULL;
    int has_nan_na = descr->has_nan_na;
    int has_string_na = descr->has_string_na;

    // 检查空值情况
    if (has_null && NpyString_isnull((npy_packed_static_string *)data)) {
        // 检查字符串 NA 值的情况
        if (!has_string_na) {
            // 检查 NaN NA 值的情况
            if (has_nan_na) {
                // numpy 将 NaN 视为真值,与 Python 保持一致
                return 1;
            }
            else {
                return 0;
            }
        }
    }

    // 返回字符串长度是否非零
    return NpyString_size((npy_packed_static_string *)data) != 0;
}

// PyArray_CompareFunc 的实现
// 按照字符码点比较 Unicode 字符串
int
compare(void *a, void *b, void *arr)
{
    // 获取描述器
    PyArray_StringDTypeObject *descr = (PyArray_StringDTypeObject *)PyArray_DESCR(arr);
    // 获取分配器并锁定互斥量
    NpyString_acquire_allocator(descr);
    // 执行比较操作
    int ret = _compare(a, b, descr, descr);
    // 释放分配给 NpyString 的内存空间
    NpyString_release_allocator(descr->allocator);
    // 返回比较结果
    return ret;
}

// _compare 函数的实现
// 比较两个 PyArray_StringDTypeObject 对象的字符串
int
_compare(void *a, void *b, PyArray_StringDTypeObject *descr_a,
         PyArray_StringDTypeObject *descr_b)
{
    // 获取分配器
    npy_string_allocator *allocator_a = descr_a->allocator;
    npy_string_allocator *allocator_b = descr_b->allocator;
    // 获取描述符 descr_b 的分配器 allocator,用于字符串分配器的操作

    // descr_a and descr_b are either the same object or objects
    // that are equal, so we can safely refer only to descr_a.
    // This is enforced in the resolve_descriptors for comparisons
    // descr_a 和 descr_b 要么是同一个对象,要么是相等的对象,因此我们可以安全地只引用 descr_a。
    // 这在解析描述符用于比较时是强制执行的。

    // Note that even though the default_string isn't checked in comparisons,
    // it will still be the same for both descrs because the value of
    // default_string is always the empty string unless na_object is a string.
    // 注意,即使在比较中没有检查 default_string,它在两个描述符中仍将是相同的,
    // 因为除非 na_object 是字符串,否则 default_string 的值始终为空字符串。

    int has_null = descr_a->na_object != NULL;
    // 检查 descr_a 是否具有空值对象 na_object

    int has_string_na = descr_a->has_string_na;
    // 检查 descr_a 是否有字符串的 NA 值

    int has_nan_na = descr_a->has_nan_na;
    // 检查 descr_a 是否有 NaN 的 NA 值

    npy_static_string *default_string = &descr_a->default_string;
    // 获取描述符 descr_a 的默认静态字符串指针 default_string

    const npy_packed_static_string *ps_a = (npy_packed_static_string *)a;
    // 将 a 转换为 npy_packed_static_string 指针类型 ps_a

    npy_static_string s_a = {0, NULL};
    // 初始化静态字符串 s_a,长度为 0,内容为空

    int a_is_null = NpyString_load(allocator_a, ps_a, &s_a);
    // 使用 allocator_a 加载 ps_a 指向的字符串数据到 s_a 中,返回是否为 null 的标志

    const npy_packed_static_string *ps_b = (npy_packed_static_string *)b;
    // 将 b 转换为 npy_packed_static_string 指针类型 ps_b

    npy_static_string s_b = {0, NULL};
    // 初始化静态字符串 s_b,长度为 0,内容为空

    int b_is_null = NpyString_load(allocator_b, ps_b, &s_b);
    // 使用 allocator_b 加载 ps_b 指向的字符串数据到 s_b 中,返回是否为 null 的标志

    if (NPY_UNLIKELY(a_is_null == -1 || b_is_null == -1)) {
        // 如果加载字符串失败(返回 -1)
        char *msg = "Failed to load string in string comparison";
        // 错误消息字符串
        npy_gil_error(PyExc_MemoryError, msg);
        // 抛出内存错误异常
        return 0;
        // 返回 0 表示比较失败
    }
    else if (NPY_UNLIKELY(a_is_null || b_is_null)) {
        // 如果任一字符串为 null
        if (has_null && !has_string_na) {
            // 如果描述符允许 null 值且没有字符串 NA 值
            if (has_nan_na) {
                // 如果有 NaN 的 NA 值
                if (a_is_null) {
                    return 1;
                    // a 是 null,返回 1
                }
                else if (b_is_null) {
                    return -1;
                    // b 是 null,返回 -1
                }
            }
            else {
                // 没有 NaN 的 NA 值,报错
                npy_gil_error(
                        PyExc_ValueError,
                        "Cannot compare null that is not a nan-like value");
                // 抛出值错误异常
                return 0;
                // 返回 0 表示比较失败
            }
        }
        else {
            // 如果描述符不允许 null 值或有字符串 NA 值
            if (a_is_null) {
                s_a = *default_string;
                // 将 s_a 设置为默认字符串
            }
            if (b_is_null) {
                s_b = *default_string;
                // 将 s_b 设置为默认字符串
            }
        }
    }
    // 返回字符串 s_a 和 s_b 的比较结果
    return NpyString_cmp(&s_a, &s_b);
}

// PyArray_ArgFunc
// 返回数组中具有最高Unicode代码点的元素的索引。
int
argmax(char *data, npy_intp n, npy_intp *max_ind, void *arr)
{
    // 获取数组描述符
    PyArray_Descr *descr = PyArray_DESCR(arr);
    // 获取元素大小
    npy_intp elsize = descr->elsize;
    // 初始化最大索引为0
    *max_ind = 0;
    // 遍历数组
    for (int i = 1; i < n; i++) {
        // 比较当前元素与当前最大元素的Unicode代码点
        if (compare(data + i * elsize, data + (*max_ind) * elsize, arr) > 0) {
            // 更新最大元素的索引
            *max_ind = i;
        }
    }
    return 0;
}

// PyArray_ArgFunc
// 返回数组中具有最低Unicode代码点的元素的索引。
int
argmin(char *data, npy_intp n, npy_intp *min_ind, void *arr)
{
    // 获取数组描述符
    PyArray_Descr *descr = PyArray_DESCR(arr);
    // 获取元素大小
    npy_intp elsize = descr->elsize;
    // 初始化最小索引为0
    *min_ind = 0;
    // 遍历数组
    for (int i = 1; i < n; i++) {
        // 比较当前元素与当前最小元素的Unicode代码点
        if (compare(data + i * elsize, data + (*min_ind) * elsize, arr) < 0) {
            // 更新最小元素的索引
            *min_ind = i;
        }
    }
    return 0;
}

static PyArray_StringDTypeObject *
stringdtype_ensure_canonical(PyArray_StringDTypeObject *self)
{
    // 增加引用计数,确保字符串数据类型对象规范化
    Py_INCREF(self);
    return self;
}

static int
stringdtype_clear_loop(void *NPY_UNUSED(traverse_context),
                       const PyArray_Descr *descr, char *data, npy_intp size,
                       npy_intp stride, NpyAuxData *NPY_UNUSED(auxdata))
{
    // 获取字符串数据类型对象
    PyArray_StringDTypeObject *sdescr = (PyArray_StringDTypeObject *)descr;
    // 获取字符串分配器
    npy_string_allocator *allocator = NpyString_acquire_allocator(sdescr);
    // 遍历数据,释放每个字符串
    while (size--) {
        npy_packed_static_string *sdata = (npy_packed_static_string *)data;
        // 如果数据不为空,释放字符串内存
        if (data != NULL && NpyString_free(sdata, allocator) < 0) {
            // 在清理循环中发生内存错误时,抛出异常
            npy_gil_error(PyExc_MemoryError,
                          "String deallocation failed in clear loop");
            goto fail;
        }
        // 移动到下一个字符串
        data += stride;
    }
    // 释放字符串分配器
    NpyString_release_allocator(allocator);
    return 0;

fail:
    // 失败时释放字符串分配器
    NpyString_release_allocator(allocator);
    return -1;
}

static int
stringdtype_get_clear_loop(void *NPY_UNUSED(traverse_context),
                           PyArray_Descr *NPY_UNUSED(descr),
                           int NPY_UNUSED(aligned),
                           npy_intp NPY_UNUSED(fixed_stride),
                           PyArrayMethod_TraverseLoop **out_loop,
                           NpyAuxData **NPY_UNUSED(out_auxdata),
                           NPY_ARRAYMETHOD_FLAGS *flags)
{
    // 设置标志以避免浮点错误
    *flags = NPY_METH_NO_FLOATINGPOINT_ERRORS;
    // 设置清理循环函数指针
    *out_loop = &stringdtype_clear_loop;
    return 0;
}

static int
stringdtype_is_known_scalar_type(PyArray_DTypeMeta *cls,
                                 PyTypeObject *pytype)
{
    // 检查Python内建类型是否为已知的标量类型
    if (python_builtins_are_known_scalar_types(cls, pytype)) {
        return 1;
    }
    // 接受所有内建的numpy数据类型

    return 1;
}
    // 如果 pytype 是以下任意一种数组类型,则返回 1
    else if (pytype == &PyBoolArrType_Type ||
             pytype == &PyByteArrType_Type ||
             pytype == &PyShortArrType_Type ||
             pytype == &PyIntArrType_Type ||
             pytype == &PyLongArrType_Type ||
             pytype == &PyLongLongArrType_Type ||
             pytype == &PyUByteArrType_Type ||
             pytype == &PyUShortArrType_Type ||
             pytype == &PyUIntArrType_Type ||
             pytype == &PyULongArrType_Type ||
             pytype == &PyULongLongArrType_Type ||
             pytype == &PyHalfArrType_Type ||
             pytype == &PyFloatArrType_Type ||
             pytype == &PyDoubleArrType_Type ||
             pytype == &PyLongDoubleArrType_Type ||
             pytype == &PyCFloatArrType_Type ||
             pytype == &PyCDoubleArrType_Type ||
             pytype == &PyCLongDoubleArrType_Type ||
             pytype == &PyIntpArrType_Type ||
             pytype == &PyUIntpArrType_Type ||
             pytype == &PyDatetimeArrType_Type ||
             pytype == &PyTimedeltaArrType_Type)
    {
        // 返回 1 表示 pytype 是数组类型之一
        return 1;
    }
    // 否则返回 0
    return 0;
}

// 结束函数 stringdtype_finalize_descr

PyArray_Descr *
stringdtype_finalize_descr(PyArray_Descr *dtype)
{
    // 将传入的 dtype 转换为 PyArray_StringDTypeObject 类型
    PyArray_StringDTypeObject *sdtype = (PyArray_StringDTypeObject *)dtype;
    // 如果 sdtype 指向的数组未被所有者拥有
    if (sdtype->array_owned == 0) {
        // 标记数组已被所有者拥有
        sdtype->array_owned = 1;
        // 增加 dtype 的引用计数
        Py_INCREF(dtype);
        // 返回原始的 dtype
        return dtype;
    }
    // 否则创建一个新的 PyArray_StringDTypeObject 实例,使用 sdtype 的 na_object 和 coerce 属性
    PyArray_StringDTypeObject *ret = (PyArray_StringDTypeObject *)new_stringdtype_instance(
            sdtype->na_object, sdtype->coerce);
    // 标记新实例的数组已被所有者拥有
    ret->array_owned = 1;
    // 返回新实例的描述符
    return (PyArray_Descr *)ret;
}

// 静态数组 PyArray_StringDType_Slots 的定义和初始化
static PyType_Slot PyArray_StringDType_Slots[] = {
        {NPY_DT_common_instance, &common_instance},
        {NPY_DT_common_dtype, &common_dtype},
        {NPY_DT_discover_descr_from_pyobject,
         &string_discover_descriptor_from_pyobject},
        {NPY_DT_setitem, &stringdtype_setitem},
        {NPY_DT_getitem, &stringdtype_getitem},
        {NPY_DT_ensure_canonical, &stringdtype_ensure_canonical},
        {NPY_DT_PyArray_ArrFuncs_nonzero, &nonzero},
        {NPY_DT_PyArray_ArrFuncs_compare, &compare},
        {NPY_DT_PyArray_ArrFuncs_argmax, &argmax},
        {NPY_DT_PyArray_ArrFuncs_argmin, &argmin},
        {NPY_DT_get_clear_loop, &stringdtype_get_clear_loop},
        {NPY_DT_finalize_descr, &stringdtype_finalize_descr},
        {_NPY_DT_is_known_scalar_type, &stringdtype_is_known_scalar_type},
        {0, NULL}};

// 创建新的 StringDType 实例
static PyObject *
stringdtype_new(PyTypeObject *NPY_UNUSED(cls), PyObject *args, PyObject *kwds)
{
    // 定义关键字参数数组
    static char *kwargs_strs[] = {"coerce", "na_object", NULL};

    PyObject *na_object = NULL;
    int coerce = 1;

    // 使用 PyArg_ParseTupleAndKeywords 解析参数
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$pO&:StringDType",
                                     kwargs_strs, &coerce,
                                     _not_NoValue, &na_object)) {
        return NULL;
    }

    // 返回创建的新 StringDType 实例
    return new_stringdtype_instance(na_object, coerce);
}

// 释放 StringDType 对象的内存
static void
stringdtype_dealloc(PyArray_StringDTypeObject *self)
{
    // 释放 na_object 的引用
    Py_XDECREF(self->na_object);
    // 如果 allocator 不为空,则释放其分配的资源
    if (self->allocator != NULL) {
        NpyString_free_allocator(self->allocator);
    }
    // 释放 na_name 和 default_string 的内存
    PyMem_RawFree((char *)self->na_name.buf);
    PyMem_RawFree((char *)self->default_string.buf);
    // 调用父类的 dealloc 方法释放对象内存
    PyArrayDescr_Type.tp_dealloc((PyObject *)self);
}

// 返回 StringDType 对象的字符串表示形式
static PyObject *
stringdtype_repr(PyArray_StringDTypeObject *self)
{
    PyObject *ret = NULL;
    // 借用 na_object 的引用
    PyObject *na_object = self->na_object;
    int coerce = self->coerce;

    // 根据 na_object 和 coerce 属性生成不同的字符串表示形式
    if (na_object != NULL && coerce == 0) {
        ret = PyUnicode_FromFormat("StringDType(na_object=%R, coerce=False)",
                                   na_object);
    }
    else if (na_object != NULL) {
        ret = PyUnicode_FromFormat("StringDType(na_object=%R)", na_object);
    }
    else if (coerce == 0) {
        ret = PyUnicode_FromFormat("StringDType(coerce=False)", coerce);
    }
    else {
        ret = PyUnicode_FromString("StringDType()");
    }

    return ret;
}

// 实现 __reduce__ 魔法方法以重建 StringDType 对象
// 导入 "numpy._core._internal" 模块中的 "_convert_to_stringdtype_kwargs" 函数,
// 并将其存储在全局变量 npy_thread_unsafe_state._convert_to_stringdtype_kwargs 中。
// 这个操作并不是性能关键,仅仅是为了方便使用 Python 中的 pickle 模块进行对象序列化。
static PyObject *
stringdtype__reduce__(PyArray_StringDTypeObject *self, PyObject *NPY_UNUSED(args))
{
    npy_cache_import("numpy._core._internal", "_convert_to_stringdtype_kwargs",
                     &npy_thread_unsafe_state._convert_to_stringdtype_kwargs);

    // 如果未能成功导入 _convert_to_stringdtype_kwargs 函数,返回 NULL 表示错误。
    if (npy_thread_unsafe_state._convert_to_stringdtype_kwargs == NULL) {
        return NULL;
    }

    // 如果 self->na_object 不为 NULL,则返回一个包含三个元素的元组:
    // (npy_thread_unsafe_state._convert_to_stringdtype_kwargs, self->coerce, self->na_object)。
    if (self->na_object != NULL) {
        return Py_BuildValue(
                "O(iO)", npy_thread_unsafe_state._convert_to_stringdtype_kwargs,
                self->coerce, self->na_object);
    }

    // 如果 self->na_object 为 NULL,则返回一个包含两个元素的元组:
    // (npy_thread_unsafe_state._convert_to_stringdtype_kwargs, self->coerce)。
    return Py_BuildValue(
            "O(i)", npy_thread_unsafe_state._convert_to_stringdtype_kwargs,
            self->coerce);
}

// 定义 PyArray_StringDType 对象的方法列表
static PyMethodDef PyArray_StringDType_methods[] = {
        {
                "__reduce__",                               // 方法名
                (PyCFunction)stringdtype__reduce__,         // 方法实现函数
                METH_NOARGS,                                // 方法接受的参数类型标志
                "Reduction method for a StringDType object", // 方法的文档字符串
        },
        {NULL, NULL, 0, NULL},                              // 方法列表结束标志
};

// 定义 PyArray_StringDType 对象的成员变量列表
static PyMemberDef PyArray_StringDType_members[] = {
        {"na_object",                                   // 成员变量名
         T_OBJECT_EX,                                   // 变量的数据类型
         offsetof(PyArray_StringDTypeObject, na_object), // 变量在结构体中的偏移量
         READONLY,                                      // 变量的标志,表示只读
         "The missing value object associated with the dtype instance"}, // 变量的文档字符串
        {"coerce",                                      // 成员变量名
         T_BOOL,                                        // 变量的数据类型
         offsetof(PyArray_StringDTypeObject, coerce),   // 变量在结构体中的偏移量
         READONLY,                                      // 变量的标志,表示只读
         "Controls whether non-string values should be coerced to string"}, // 变量的文档字符串
        {NULL, 0, 0, 0, NULL},                           // 成员变量列表结束标志
};

// 定义 PyArray_StringDType 对象的富比较方法
static PyObject *
PyArray_StringDType_richcompare(PyObject *self, PyObject *other, int op)
{
    // 如果 op 不是 Py_EQ 或 Py_NE,或者 other 不是 self 的同一类型,返回 NotImplemented。
    if (((op != Py_EQ) && (op != Py_NE)) ||
        (Py_TYPE(other) != Py_TYPE(self))) {
        Py_INCREF(Py_NotImplemented);
        return Py_NotImplemented;
    }

    // 将 self 和 other 转换为 PyArray_StringDTypeObject 类型,因为我们已知它们是该类型的实例。
    PyArray_StringDTypeObject *sself = (PyArray_StringDTypeObject *)self;
    PyArray_StringDTypeObject *sother = (PyArray_StringDTypeObject *)other;

    // 调用 _eq_comparison 函数比较 self 和 other 的 coerce 和 na_object 成员变量。
    int eq = _eq_comparison(sself->coerce, sother->coerce, sself->na_object,
                            sother->na_object);

    // 如果 _eq_comparison 返回 -1,表示比较出错,返回 NULL。
    if (eq == -1) {
        return NULL;
    }

    // 根据比较结果和 op 的值返回 Py_True 或 Py_False。
    if ((op == Py_EQ && eq) || (op == Py_NE && !eq)) {
        Py_INCREF(Py_True);
        return Py_True;
    }
    Py_INCREF(Py_False);
    return Py_False;
}

// 定义 PyArray_StringDType 对象的哈希计算方法
static Py_hash_t
PyArray_StringDType_hash(PyObject *self)
{
    // 将 self 转换为 PyArray_StringDTypeObject 类型。
    PyArray_StringDTypeObject *sself = (PyArray_StringDTypeObject *)self;
    PyObject *hash_tup = NULL;

    // 如果 sself->na_object 不为 NULL,则构建一个包含两个元素的元组 (sself->coerce, sself->na_object)。
    // 否则,构建一个包含一个元素的元组 (sself->coerce)。
    if (sself->na_object != NULL) {
        hash_tup = Py_BuildValue("(iO)", sself->coerce, sself->na_object);
    }
    else {
        hash_tup = Py_BuildValue("(i)", sself->coerce);
    }

    // 计算元组 hash_tup 的哈希值,并返回结果。
    Py_hash_t ret = PyObject_Hash(hash_tup);
    Py_DECREF(hash_tup);
    return ret;
}
"""
/*
 * This is the basic things that you need to create a Python Type/Class in C.
 * However, there is a slight difference here because we create a
 * PyArray_DTypeMeta, which is a larger struct than a typical type.
 * (This should get a bit nicer eventually with Python >3.11.)
 */
*/

PyArray_DTypeMeta PyArray_StringDType = {
        {{
                // 设置类型名称为 "numpy.dtypes.StringDType",基本大小为 PyArray_StringDTypeObject 的大小
                PyVarObject_HEAD_INIT(NULL, 0).tp_name =
                        "numpy.dtypes.StringDType",
                // 分配内存空间大小为 PyArray_StringDTypeObject 的大小
                .tp_basicsize = sizeof(PyArray_StringDTypeObject),
                // 设置构造函数为 stringdtype_new
                .tp_new = stringdtype_new,
                // 设置析构函数为 stringdtype_dealloc
                .tp_dealloc = (destructor)stringdtype_dealloc,
                // 设置对象的字符串表示形式为 stringdtype_repr
                .tp_repr = (reprfunc)stringdtype_repr,
                // 设置对象的字符串形式为 stringdtype_repr
                .tp_str = (reprfunc)stringdtype_repr,
                // 设置对象的方法为 PyArray_StringDType_methods
                .tp_methods = PyArray_StringDType_methods,
                // 设置对象的成员为 PyArray_StringDType_members
                .tp_members = PyArray_StringDType_members,
                // 设置对象的比较函数为 PyArray_StringDType_richcompare
                .tp_richcompare = PyArray_StringDType_richcompare,
                // 设置对象的哈希函数为 PyArray_StringDType_hash
                .tp_hash = PyArray_StringDType_hash,
        }},
        /* rest, filled in during DTypeMeta initialization */
};

NPY_NO_EXPORT int
init_string_dtype(void)
{
    // 获取字符串类型的强制转换列表
    PyArrayMethod_Spec **PyArray_StringDType_casts = get_casts();

    // 字符串类型的元数据规范
    PyArrayDTypeMeta_Spec PyArray_StringDType_DTypeSpec = {
            // 标志为 NPY_DT_PARAMETRIC
            .flags = NPY_DT_PARAMETRIC,
            // 类型对象为 PyUnicode_Type
            .typeobj = &PyUnicode_Type,
            // 槽位为 PyArray_StringDType_Slots
            .slots = PyArray_StringDType_Slots,
            // 强制转换为 PyArray_StringDType_casts
            .casts = PyArray_StringDType_casts,
    };

    /* Loaded dynamically, so needs to be set here: */
    // 将 PyArray_StringDType 的类型设置为 PyArrayDTypeMeta_Type
    ((PyObject *)&PyArray_StringDType)->ob_type = &PyArrayDTypeMeta_Type;
    // 将 PyArray_StringDType 的基类设置为 PyArrayDescr_Type
    ((PyTypeObject *)&PyArray_StringDType)->tp_base = &PyArrayDescr_Type;
    // 如果 PyType_Ready((PyTypeObject *)&PyArray_StringDType) 小于 0,则返回 -1
    if (PyType_Ready((PyTypeObject *)&PyArray_StringDType) < 0) {
        return -1;
    }

    // 如果 dtypemeta_initialize_struct_from_spec 初始化失败,则返回 -1
    if (dtypemeta_initialize_struct_from_spec(
                &PyArray_StringDType, &PyArray_StringDType_DTypeSpec, 1) < 0) {
        return -1;
    }

    // 获取默认的描述符
    PyArray_Descr *singleton =
            NPY_DT_CALL_default_descr(&PyArray_StringDType);

    // 如果 singleton 为空,则返回 -1
    if (singleton == NULL) {
        return -1;
    }

    // 设置 PyArray_StringDType 的单例为 singleton
    PyArray_StringDType.singleton = singleton;
    // 设置 PyArray_StringDType 的类型编号为 NPY_VSTRING
    PyArray_StringDType.type_num = NPY_VSTRING;

    // 释放 PyArray_StringDType_casts 的内存
    for (int i = 0; PyArray_StringDType_casts[i] != NULL; i++) {
        PyMem_Free(PyArray_StringDType_casts[i]->dtypes);
        PyMem_Free(PyArray_StringDType_casts[i]);
    }

    PyMem_Free(PyArray_StringDType_casts);

    // 返回成功
    return 0;
}

int
free_and_copy(npy_string_allocator *in_allocator,
              npy_string_allocator *out_allocator,
              const npy_packed_static_string *in,
              npy_packed_static_string *out, const char *location)
{
    // 释放输出的字符串内存
    if (NpyString_free(out, out_allocator) < 0) {
        // 如果释放失败,则报错并返回 -1
        npy_gil_error(PyExc_MemoryError, "Failed to deallocate string in %s", location);
        return -1;
    }
    // 复制输入到输出字符串
    if (NpyString_dup(in, out, in_allocator, out_allocator) < 0) {
        // 如果复制失败,则报错并返回 -1
        npy_gil_error(PyExc_MemoryError, "Failed to allocate string in %s", location);
        return -1;
    }
    // 操作成功,返回 0
    return 0;
}
/*
 * 使用一个预定义的 npy_static_string 实例,分配到栈上并初始化为 {0, NULL},
 * 将指向这个栈上分配的未打包字符串的指针传递给该函数,用来填充新分配字符串的内容。
 */
NPY_NO_EXPORT int
load_new_string(npy_packed_static_string *out, npy_static_string *out_ss,
                size_t num_bytes, npy_string_allocator *allocator,
                const char *err_context)
{
    // 将输出参数 out 强制转换为 npy_packed_static_string 指针
    npy_packed_static_string *out_pss = (npy_packed_static_string *)out;
    // 如果调用 NpyString_free 函数释放 out_pss 失败
    if (NpyString_free(out_pss, allocator) < 0) {
        // 报告内存错误,并指明错误上下文
        npy_gil_error(PyExc_MemoryError,
                      "Failed to deallocate string in %s", err_context);
        return -1;  // 返回错误码
    }
    // 调用 NpyString_newemptysize 函数尝试分配 num_bytes 大小的新字符串到 out_pss
    if (NpyString_newemptysize(num_bytes, out_pss, allocator) < 0) {
        // 报告内存错误,并指明错误上下文
        npy_gil_error(PyExc_MemoryError,
                      "Failed to allocate string in %s", err_context);
        return -1;  // 返回错误码
    }
    // 调用 NpyString_load 函数加载字符串到 out_ss,并使用 allocator 进行分配
    if (NpyString_load(allocator, out_pss, out_ss) == -1) {
        // 报告内存错误,并指明错误上下文
        npy_gil_error(PyExc_MemoryError,
                      "Failed to load string in %s", err_context);
        return -1;  // 返回错误码
    }
    // 操作成功完成,返回成功码
    return 0;
}