NumPy-源码解析-六十三-

34 阅读1小时+

NumPy 源码解析(六十三)

.\numpy\numpy\_core\src\multiarray\datetime_busday.h

/*
 * This header guards prevent multiple inclusions of the header file
 * NUMPY_CORE_SRC_MULTIARRAY_DATETIME_BUSDAY_H_ defines a unique identifier
 * to avoid redefinition of the content between the #ifndef and #endif directives.
 */
#ifndef NUMPY_CORE_SRC_MULTIARRAY_DATETIME_BUSDAY_H_
#define NUMPY_CORE_SRC_MULTIARRAY_DATETIME_BUSDAY_H_

/*
 * NPY_NO_EXPORT is a macro used to specify that the following function
 * should not be exposed when compiling as a shared library.
 * 
 * array_busday_offset is a function that computes business day offsets
 * for NumPy arrays. It is intended to be called from Python.
 */
NPY_NO_EXPORT PyObject *
array_busday_offset(PyObject *NPY_UNUSED(self),
                      PyObject *args, PyObject *kwds);

/*
 * NPY_NO_EXPORT is a macro used to specify that the following function
 * should not be exposed when compiling as a shared library.
 * 
 * array_busday_count is a function that counts business days
 * between dates for NumPy arrays. It is intended to be called from Python.
 */
NPY_NO_EXPORT PyObject *
array_busday_count(PyObject *NPY_UNUSED(self),
                      PyObject *args, PyObject *kwds);

/*
 * NPY_NO_EXPORT is a macro used to specify that the following function
 * should not be exposed when compiling as a shared library.
 * 
 * array_is_busday is a function that checks whether dates are business days
 * for NumPy arrays. It is intended to be called from Python.
 */
NPY_NO_EXPORT PyObject *
array_is_busday(PyObject *NPY_UNUSED(self),
                      PyObject *args, PyObject *kwds);

#endif  /* NUMPY_CORE_SRC_MULTIARRAY_DATETIME_BUSDAY_H_ */

.\numpy\numpy\_core\src\multiarray\datetime_busdaycal.c

/*
 * This file implements an object encapsulating a business day
 * calendar object for accelerating NumPy datetime business day functions.
 *
 * Written by Mark Wiebe (mwwiebe@gmail.com)
 * Copyright (c) 2011 by Enthought, Inc.
 *
 * See LICENSE.txt for the license.
 */

// 设置以 NPY_API_VERSION 版本为准,禁用已弃用的 NumPy API
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
// 定义 _MULTIARRAYMODULE,可能用于多维数组模块的标志

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

// 引入 Python 标准库头文件
#include <Python.h>

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

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

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

// 引入共享的常用功能头文件
#include "common.h"

// 引入低级分块循环的头文件
#include "lowlevel_strided_loops.h"

// 引入日期时间扩展的头文件
#include "_datetime.h"

// 引入工作日计算相关的头文件
#include "datetime_busday.h"

// 引入工作日历算法的头文件
#include "datetime_busdaycal.h"

// 非导出的函数,用于转换周掩码对象为布尔数组
NPY_NO_EXPORT int
PyArray_WeekMaskConverter(PyObject *weekmask_in, npy_bool *weekmask)
{
    // weekmask_in 赋给局部变量 obj
    PyObject *obj = weekmask_in;

    // 如果 obj 是字节对象
    if (PyBytes_Check(obj)) {
        /* accept bytes input */
        // 将字节对象转换为 UTF-8 字符串
        PyObject *obj_str = PyUnicode_FromEncodedObject(obj, NULL, NULL);
        // 如果转换失败,返回 0
        if (obj_str == NULL) {
            return 0;
        }
        // 更新 obj 为转换后的字符串对象
        obj = obj_str;
    }
    else {
        // 增加 obj 的引用计数
        Py_INCREF(obj);
    }

    // 如果 obj 是 Unicode 对象
    if (PyUnicode_Check(obj)) {
        // 获取 Unicode 对象的长度和 UTF-8 编码字符串
        Py_ssize_t len;
        char const *str = PyUnicode_AsUTF8AndSize(obj, &len);
        // 如果获取失败,释放 obj 并返回 0
        if (str == NULL) {
            Py_DECREF(obj);
            return 0;
        }

        // 如果字符串长度为 7,处理类似 "1111100" 的字符串
        if (len == 7) {
            // 遍历字符串的每个字符
            for (int i = 0; i < 7; ++i) {
                // 根据字符设置对应的 weekmask 值
                switch(str[i]) {
                    case '0':
                        weekmask[i] = 0;
                        break;
                    case '1':
                        weekmask[i] = 1;
                        break;
                    default:
                        // 如果遇到非预期字符,跳转到 general_weekmask_string 处理
                        goto general_weekmask_string;
                }
            }

            // 跳转到完成处理的标签
            goto finish;
        }

        // 如果长度不为 7,跳转到处理通用 weekmask 字符串的标签
        general_weekmask_string:
        ;
    }

    // 完成处理,释放 obj 对象
    finish:
    Py_DECREF(obj);
    return 1;
}
general_weekmask_string:
    /* 一般的工作日掩码字符串,例如 "SatSun""Mon Tue Wed" */
    memset(weekmask, 0, 7);  // 将 weekmask 数组初始化为零,长度为 7
    for (Py_ssize_t i = 0; i < len; i += 3) {  // 循环处理字符串,每次增加 3 个字符长度
        while (isspace(str[i]))  // 跳过空白字符
            ++i;

        if (i == len) {  // 如果已经处理完字符串,跳转到结束标签
            goto finish;
        }
        else if (i + 2 >= len) {  // 如果剩余字符不足 3 个,说明字符串无效,跳转到无效字符串标签
            goto invalid_weekmask_string;
        }

        switch (str[i]) {  // 根据当前字符判断工作日掩码
            case 'M':  // 处理 "Mon" 开头的情况
                if (str[i+1] == 'o' && str[i+2] == 'n') {
                    weekmask[0] = 1;  // 星期一设为工作日
                }
                else {
                    goto invalid_weekmask_string;  // 字符串无效,跳转到无效字符串标签
                }
                break;
            case 'T':  // 处理 "Tue""Thu" 开头的情况
                if (str[i+1] == 'u' && str[i+2] == 'e') {
                    weekmask[1] = 1;  // 星期二设为工作日
                }
                else if (str[i+1] == 'h' && str[i+2] == 'u') {
                    weekmask[3] = 1;  // 星期四设为工作日
                }
                else {
                    goto invalid_weekmask_string;  // 字符串无效,跳转到无效字符串标签
                }
                break;
            case 'W':  // 处理 "Wed" 开头的情况
                if (str[i+1] == 'e' && str[i+2] == 'd') {
                    weekmask[2] = 1;  // 星期三设为工作日
                }
                else {
                    goto invalid_weekmask_string;  // 字符串无效,跳转到无效字符串标签
                }
                break;
            case 'F':  // 处理 "Fri" 开头的情况
                if (str[i+1] == 'r' && str[i+2] == 'i') {
                    weekmask[4] = 1;  // 星期五设为工作日
                }
                else {
                    goto invalid_weekmask_string;  // 字符串无效,跳转到无效字符串标签
                }
                break;
            case 'S':  // 处理 "Sat""Sun" 开头的情况
                if (str[i+1] == 'a' && str[i+2] == 't') {
                    weekmask[5] = 1;  // 星期六设为工作日
                }
                else if (str[i+1] == 'u' && str[i+2] == 'n') {
                    weekmask[6] = 1;  // 星期日设为工作日
                }
                else {
                    goto invalid_weekmask_string;  // 字符串无效,跳转到无效字符串标签
                }
                break;
            default:
                goto invalid_weekmask_string;  // 字符串无效,跳转到无效字符串标签
        }
    }

finish:  // 成功处理字符串,跳转到结束
    /* Something like [1,1,1,1,1,0,0] */  // 返回的 weekmask 数组表示的是工作日掩码
    # 如果对象是一个序列对象
    else if (PySequence_Check(obj)) {
        # 检查序列对象的长度是否为7,或者如果是数组对象,则检查其维度是否为1
        if (PySequence_Size(obj) != 7 ||
                        (PyArray_Check(obj) &&
                         PyArray_NDIM((PyArrayObject *)obj) != 1)) {
            # 设置异常信息,表示业务日期的工作日掩码数组必须长度为7
            PyErr_SetString(PyExc_ValueError,
                "A business day weekmask array must have length 7");
            # 减少对象的引用计数
            Py_DECREF(obj);
            # 返回0,表示操作失败
            return 0;
        }
        else {
            # 循环遍历7次,处理每个元素
            int i;

            for (i = 0; i < 7; ++i) {
                long val;
                # 获取序列对象中的第i个元素
                PyObject *f = PySequence_GetItem(obj, i);
                # 如果获取失败,则减少对象的引用计数并返回0
                if (f == NULL) {
                    Py_DECREF(obj);
                    return 0;
                }

                # 将获取的元素转换为长整型
                val = PyLong_AsLong(f);
                # 如果转换过程中出错,则减少元素的引用计数和对象的引用计数,并返回0
                if (error_converting(val)) {
                    Py_DECREF(f);
                    Py_DECREF(obj);
                    return 0;
                }
                # 根据转换后的值设置周掩码数组的对应值
                if (val == 0) {
                    weekmask[i] = 0;
                }
                else if (val == 1) {
                    weekmask[i] = 1;
                }
                else {
                    # 如果值不是0或1,则设置异常信息,表示业务日期的工作日掩码数组必须全部是1或0
                    PyErr_SetString(PyExc_ValueError,
                        "A business day weekmask array must have all "
                        "1's and 0's");
                    # 减少元素的引用计数和对象的引用计数,并返回0
                    Py_DECREF(f);
                    Py_DECREF(obj);
                    return 0;
                }
                # 减少元素的引用计数
                Py_DECREF(f);
            }

            # 跳转到完成处理的标签
            goto finish;
        }
    }

    # 设置异常信息,表示无法将对象转换为业务日期的工作日掩码数组
    PyErr_SetString(PyExc_ValueError,
            "Couldn't convert object into a business day weekmask");
    # 减少对象的引用计数
    Py_DECREF(obj);
    # 返回0,表示操作失败
    return 0;
finish:
    Py_DECREF(obj);
    return 1;
}

static int
qsort_datetime_compare(const void *elem1, const void *elem2)
{
    npy_datetime e1 = *(const npy_datetime *)elem1;
    npy_datetime e2 = *(const npy_datetime *)elem2;

    return (e1 < e2) ? -1 : (e1 == e2) ? 0 : 1;
}

/*
 * Sorts the array of dates provided in place and removes
 * NaT, duplicates and any date which is already excluded on account
 * of the weekmask.
 *
 * Returns the number of dates left after removing weekmask-excluded
 * dates.
 */
NPY_NO_EXPORT void
normalize_holidays_list(npy_holidayslist *holidays, npy_bool *weekmask)
{
    npy_datetime *dates = holidays->begin;
    npy_intp count = holidays->end - dates;

    npy_datetime lastdate = NPY_DATETIME_NAT;
    npy_intp trimcount, i;
    int day_of_week;

    /* Sort the dates */
    qsort(dates, count, sizeof(npy_datetime), &qsort_datetime_compare);

    /* Sweep through the array, eliminating unnecessary values */
    trimcount = 0;
    for (i = 0; i < count; ++i) {
        npy_datetime date = dates[i];

        /* Skip any NaT or duplicate */
        if (date != NPY_DATETIME_NAT && date != lastdate) {
            /* Get the day of the week (1970-01-05 is Monday) */
            day_of_week = (int)((date - 4) % 7);
            if (day_of_week < 0) {
                day_of_week += 7;
            }

            /*
             * If the holiday falls on a possible business day,
             * then keep it.
             */
            if (weekmask[day_of_week] == 1) {
                dates[trimcount++] = date;
                lastdate = date;
            }
        }
    }

    /* Adjust the end of the holidays array */
    holidays->end = dates + trimcount;
}

/*
 * Converts a Python input into a non-normalized list of holidays.
 *
 * IMPORTANT: This function can't do the normalization, because it doesn't
 *            know the weekmask. You must call 'normalize_holiday_list'
 *            on the result before using it.
 */
NPY_NO_EXPORT int
PyArray_HolidaysConverter(PyObject *dates_in, npy_holidayslist *holidays)
{
    PyArrayObject *dates = NULL;
    PyArray_Descr *date_dtype = NULL;
    npy_intp count;

    /* Make 'dates' into an array */
    if (PyArray_Check(dates_in)) {
        // 如果 dates_in 是已经是一个数组,则直接使用它
        dates = (PyArrayObject *)dates_in;
        Py_INCREF(dates);
    }
    else {
        PyArray_Descr *datetime_dtype;

        /* Use the datetime dtype with generic units so it fills it in */
        // 使用通用单位的 datetime 数据类型来填充日期数据
        datetime_dtype = PyArray_DescrFromType(NPY_DATETIME);
        if (datetime_dtype == NULL) {
            goto fail;
        }

        /* This steals the datetime_dtype reference */
        // 从任意输入数据创建一个新的数组
        dates = (PyArrayObject *)PyArray_FromAny(dates_in, datetime_dtype,
                                                0, 0, 0, NULL);
        if (dates == NULL) {
            goto fail;
        }
    }

    // 创建一个带有指定单位的 datetime 数据类型
    date_dtype = create_datetime_dtype_with_unit(NPY_DATETIME, NPY_FR_D);
    if (date_dtype == NULL) {
        goto fail;
    }
    # 检查是否可以安全地将 dates 数组转换为 date_dtype 类型的数组
    if (!PyArray_CanCastTypeTo(PyArray_DESCR(dates),
                                    date_dtype, NPY_SAFE_CASTING)) {
        # 设置异常信息,指示无法安全地转换提供的假日输入为日期数组
        PyErr_SetString(PyExc_ValueError, "Cannot safely convert "
                        "provided holidays input into an array of dates");
        # 转到失败处理部分
        goto fail;
    }
    
    # 检查 dates 数组的维度是否为 1
    if (PyArray_NDIM(dates) != 1) {
        # 设置异常信息,指示假日必须作为一维数组提供
        PyErr_SetString(PyExc_ValueError, "holidays must be a provided "
                        "as a one-dimensional array");
        # 转到失败处理部分
        goto fail;
    }

    /* 分配用于存储日期的内存空间 */
    count = PyArray_DIM(dates, 0);
    holidays->begin = PyArray_malloc(sizeof(npy_datetime) * count);
    if (holidays->begin == NULL) {
        # 分配内存失败,设置内存不足的异常
        PyErr_NoMemory();
        # 转到失败处理部分
        goto fail;
    }
    holidays->end = holidays->begin + count;

    /* 将数据强制转换为原始日期数组 */
    if (PyArray_CastRawArrays(count,
                            PyArray_BYTES(dates), (char *)holidays->begin,
                            PyArray_STRIDE(dates, 0), sizeof(npy_datetime),
                            PyArray_DESCR(dates), date_dtype,
                            0) != NPY_SUCCEED) {
        # 转换失败,转到失败处理部分
        goto fail;
    }

    // 减少 dates 和 date_dtype 的引用计数
    Py_DECREF(dates);
    Py_DECREF(date_dtype);

    // 返回成功标志
    return 1;
fail:
    // 释放 dates 和 date_dtype 对象的引用,防止内存泄漏
    Py_XDECREF(dates);
    Py_XDECREF(date_dtype);
    // 返回 0,表示函数执行失败
    return 0;
}

static PyObject *
busdaycalendar_new(PyTypeObject *subtype,
                    PyObject *NPY_UNUSED(args), PyObject *NPY_UNUSED(kwds))
{
    NpyBusDayCalendar *self;

    // 分配内存给新的 NpyBusDayCalendar 对象
    self = (NpyBusDayCalendar *)subtype->tp_alloc(subtype, 0);
    if (self != NULL) {
        /* Start with an empty holidays list */
        // 初始化 holidays 为一个空列表
        self->holidays.begin = NULL;
        self->holidays.end = NULL;

        /* Set the weekmask to the default */
        // 设置 weekmask 的默认值为工作日掩码
        self->busdays_in_weekmask = 5;
        self->weekmask[0] = 1;
        self->weekmask[1] = 1;
        self->weekmask[2] = 1;
        self->weekmask[3] = 1;
        self->weekmask[4] = 1;
        self->weekmask[5] = 0;
        self->weekmask[6] = 0;
    }

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

static int
busdaycalendar_init(NpyBusDayCalendar *self, PyObject *args, PyObject *kwds)
{
    static char *kwlist[] = {"weekmask", "holidays", NULL};
    int i, busdays_in_weekmask;

    /* Clear the holidays if necessary */
    // 如果 holidays 列表不为空,则清空它
    if (self->holidays.begin != NULL) {
        PyArray_free(self->holidays.begin);
        self->holidays.begin = NULL;
        self->holidays.end = NULL;
    }

    /* Reset the weekmask to the default */
    // 重置 weekmask 为默认值
    self->busdays_in_weekmask = 5;
    self->weekmask[0] = 1;
    self->weekmask[1] = 1;
    self->weekmask[2] = 1;
    self->weekmask[3] = 1;
    self->weekmask[4] = 1;
    self->weekmask[5] = 0;
    self->weekmask[6] = 0;

    /* Parse the parameters */
    // 解析参数
    if (!PyArg_ParseTupleAndKeywords(args, kwds,
                        "|O&O&:busdaycal", kwlist,
                        &PyArray_WeekMaskConverter, &self->weekmask[0],
                        &PyArray_HolidaysConverter, &self->holidays)) {
        return -1;
    }

    /* Count the number of business days in a week */
    // 统计一周中的工作日数量
    busdays_in_weekmask = 0;
    for (i = 0; i < 7; ++i) {
        busdays_in_weekmask += self->weekmask[i];
    }
    self->busdays_in_weekmask = busdays_in_weekmask;

    /* Normalize the holidays list */
    // 标准化 holidays 列表
    normalize_holidays_list(&self->holidays, self->weekmask);

    // 检查 weekmask 是否全为零,若是则抛出 ValueError 异常
    if (self->busdays_in_weekmask == 0) {
        PyErr_SetString(PyExc_ValueError,
                "Cannot construct a numpy.busdaycal with a weekmask of "
                "all zeros");
        return -1;
    }

    // 返回 0,表示初始化成功
    return 0;
}

static void
busdaycalendar_dealloc(NpyBusDayCalendar *self)
{
    /* Clear the holidays */
    // 清空 holidays 列表
    if (self->holidays.begin != NULL) {
        PyArray_free(self->holidays.begin);
        self->holidays.begin = NULL;
        self->holidays.end = NULL;
    }

    // 释放对象的内存
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
busdaycalendar_weekmask_get(NpyBusDayCalendar *self, void *NPY_UNUSED(ignored))
{
    PyArrayObject *ret;
    npy_intp size = 7;

    /* Allocate a 7-element boolean array */
    // 分配一个包含 7 个元素的布尔数组
    ret = (PyArrayObject *)PyArray_SimpleNew(1, &size, NPY_BOOL);
    if (ret == NULL) {
        return NULL;
    }

    /* Copy the weekmask data */
    // 复制 weekmask 的数据到返回的数组中
    memcpy(PyArray_DATA(ret), self->weekmask, 7);
    // 将 ret 转换为 PyObject 指针类型并返回
    return (PyObject *)ret;
}

static PyObject *
busdaycalendar_holidays_get(NpyBusDayCalendar *self, void *NPY_UNUSED(ignored))
{
    PyArrayObject *ret;
    PyArray_Descr *date_dtype;
    npy_intp size = self->holidays.end - self->holidays.begin;

    /* Create a date dtype */
    // 创建一个日期的数据类型
    date_dtype = create_datetime_dtype_with_unit(NPY_DATETIME, NPY_FR_D);
    if (date_dtype == NULL) {
        return NULL;
    }

    /* Allocate a date array (this steals the date_dtype reference) */
    // 分配一个日期数组(这里会接管 date_dtype 的引用)
    ret = (PyArrayObject *)PyArray_SimpleNewFromDescr(1, &size, date_dtype);
    if (ret == NULL) {
        return NULL;
    }

    /* Copy the holidays */
    // 复制节假日数据
    if (size > 0) {
        memcpy(PyArray_DATA(ret), self->holidays.begin,
                    size * sizeof(npy_datetime));
    }

    return (PyObject *)ret;
}

static PyGetSetDef busdaycalendar_getsets[] = {
    {"weekmask",
        (getter)busdaycalendar_weekmask_get,
        NULL, NULL, NULL},
    {"holidays",
        (getter)busdaycalendar_holidays_get,
        NULL, NULL, NULL},

    {NULL, NULL, NULL, NULL, NULL}
};

NPY_NO_EXPORT PyTypeObject NpyBusDayCalendar_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "numpy.busdaycalendar",
    .tp_basicsize = sizeof(NpyBusDayCalendar),
    .tp_dealloc = (destructor)busdaycalendar_dealloc,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_getset = busdaycalendar_getsets,
    .tp_init = (initproc)busdaycalendar_init,
    .tp_new = busdaycalendar_new,
};

.\numpy\numpy\_core\src\multiarray\datetime_busdaycal.h

#ifndef NUMPY_CORE_SRC_MULTIARRAY_DATETIME_BUSDAYCAL_H_
#define NUMPY_CORE_SRC_MULTIARRAY_DATETIME_BUSDAYCAL_H_

/*
 * A list of holidays, which should be sorted, not contain any
 * duplicates or NaTs, and not include any days already excluded
 * by the associated weekmask.
 *
 * The data is manually managed with PyArray_malloc/PyArray_free.
 */
typedef struct {
    npy_datetime *begin, *end;
} npy_holidayslist;

/*
 * This object encapsulates a weekmask and normalized holidays list,
 * so that the business day API can use this data without having
 * to normalize it repeatedly. All the data of this object is private
 * and cannot be modified from Python. Copies are made when giving
 * the weekmask and holidays data to Python code.
 */
typedef struct {
    PyObject_HEAD
    npy_holidayslist holidays;
    int busdays_in_weekmask;
    npy_bool weekmask[7];
} NpyBusDayCalendar;

// Declaration of the type object for NpyBusDayCalendar
extern NPY_NO_EXPORT PyTypeObject NpyBusDayCalendar_Type;


/*
 * Converts a Python input into a 7-element weekmask, where 0 means
 * weekend and 1 means business day.
 */
NPY_NO_EXPORT int
PyArray_WeekMaskConverter(PyObject *weekmask_in, npy_bool *weekmask);

/*
 * Sorts the array of dates provided in place and removes
 * NaT, duplicates and any date which is already excluded on account
 * of the weekmask.
 *
 * Returns the number of dates left after removing weekmask-excluded
 * dates.
 */
NPY_NO_EXPORT void
normalize_holidays_list(npy_holidayslist *holidays, npy_bool *weekmask);

/*
 * Converts a Python input into a non-normalized list of holidays.
 *
 * IMPORTANT: This function can't do the normalization, because it doesn't
 *            know the weekmask. You must call 'normalize_holiday_list'
 *            on the result before using it.
 */
NPY_NO_EXPORT int
PyArray_HolidaysConverter(PyObject *dates_in, npy_holidayslist *holidays);



#endif  /* NUMPY_CORE_SRC_MULTIARRAY_DATETIME_BUSDAYCAL_H_ */

.\numpy\numpy\_core\src\multiarray\datetime_strings.c

/*
 * This file implements string parsing and creation for NumPy datetime.
 *
 * Written by Mark Wiebe (mwwiebe@gmail.com)
 * Copyright (c) 2011 by Enthought, Inc.
 *
 * See LICENSE.txt for the license.
 */
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
#define _MULTIARRAYMODULE

#define PY_SSIZE_T_CLEAN
#include <Python.h>


#include "numpy/arrayobject.h"

#include "npy_config.h"


#include "numpy/arrayscalars.h"
#include "convert_datatype.h"
#include "_datetime.h"
#include "datetime_strings.h"

#include <time.h>

/*
 * Platform-specific time_t typedef. Some platforms use 32 bit, some use 64 bit
 * and we just use the default with the exception of mingw, where we must use
 * 64 bit because MSVCRT version 9 does not have the (32 bit) localtime()
 * symbol, so we need to use the 64 bit version [1].
 *
 * [1] http://thread.gmane.org/gmane.comp.gnu.mingw.user/27011
 */
#if defined(NPY_MINGW_USE_CUSTOM_MSVCR)
 typedef __time64_t NPY_TIME_T;
#else
 typedef time_t NPY_TIME_T;
#endif

/*
 * Wraps `localtime` functionality for multiple platforms. This
 * converts a time value to a time structure in the local timezone.
 * If size(NPY_TIME_T) == 4, then years must be between 1970 and 2038. If
 * size(NPY_TIME_T) == 8, then years must be later than 1970. If the years are
 * not in this range, then get_localtime() will fail on some platforms.
 *
 * Returns 0 on success, -1 on failure.
 *
 * Notes:
 * 1) If NPY_TIME_T is 32 bit (i.e. sizeof(NPY_TIME_T) == 4), then the
 *    maximum year it can represent is 2038 (see [1] for more details). Trying
 *    to use a higher date like 2041 in the 32 bit "ts" variable below will
 *    typically result in "ts" being a negative number (corresponding roughly
 *    to a year ~ 1905). If NPY_TIME_T is 64 bit, then there is no such
 *    problem in practice.
 * 2) If the "ts" argument to localtime() is negative, it represents
 *    years < 1970 both for 32 and 64 bits (for 32 bits the earliest year it can
 *    represent is 1901, while 64 bits can represent much earlier years).
 * 3) On Linux, localtime() works for negative "ts". On Windows and in Wine,
 *    localtime() as well as the localtime_s() and _localtime64_s() functions
 *    will fail for any negative "ts" and return a nonzero exit number
 *    (localtime_s, _localtime64_s) or NULL (localtime). This behavior is the
 *    same for both 32 and 64 bits.
 *
 * From this it follows that get_localtime() is only guaranteed to work
 * correctly on all platforms for years between 1970 and 2038 for 32bit
 * NPY_TIME_T and years higher than 1970 for 64bit NPY_TIME_T. For
 * multiplatform code, get_localtime() should never be used outside of this
 * range.
 *
 * [1] https://en.wikipedia.org/wiki/Year_2038_problem
 */
static int
get_localtime(NPY_TIME_T *ts, struct tm *tms)
{
    char *func_name = "<unknown>";
#if defined(_WIN32)
 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
    // Use localtime_s() on Windows platforms with MSVC 2005 or newer
    if (localtime_s(tms, ts) != 0) {
        func_name = "localtime_s";
        goto fail;

    // Use localtime_s() on Windows platforms with MSVC 2005 or newer
    if (localtime_s(tms, ts) != 0) {
        func_name = "localtime_s";
        // If localtime_s() fails, set func_name and jump to fail label
        goto fail;
    }
#else
    // Use localtime() for other Windows platforms and non-Windows platforms
    struct tm *tm_result = localtime(ts);
    if (tm_result == NULL) {
        func_name = "localtime";
        // If localtime() fails, set func_name and jump to fail label
        goto fail;
    }
    // Copy the result from tm_result to tms
    *tms = *tm_result;
#endif

    // Return success (0) if localtime function succeeded
    return 0;

fail:
    // Print an error message indicating the function that failed
    PyErr_Format(PyExc_ValueError, "%s failed", func_name);
    // Return failure (-1) if localtime function failed
    return -1;
}
    }
 #elif defined(NPY_MINGW_USE_CUSTOM_MSVCR)
    // 如果定义了 NPY_MINGW_USE_CUSTOM_MSVCR,则使用 _localtime64_s 函数获取本地时间
    if (_localtime64_s(tms, ts) != 0) {
        // 如果 _localtime64_s 函数返回非零值,表示调用失败,记录函数名并跳转到失败处理标签
        func_name = "_localtime64_s";
        goto fail;
    }
 #else
    // 否则,使用标准库函数 localtime 获取本地时间
    struct tm *tms_tmp;
    tms_tmp = localtime(ts);
    // 如果 localtime 返回空指针,则表示调用失败,记录函数名并跳转到失败处理标签
    if (tms_tmp == NULL) {
        func_name = "localtime";
        goto fail;
    }
    // 复制获取到的时间结构体到指定的 tms 结构体中
    memcpy(tms, tms_tmp, sizeof(struct tm));
 #endif
#else
    // 如果调用 localtime_r(ts, tms) 失败,则设置 func_name 并跳转到 fail 标签处
    if (localtime_r(ts, tms) == NULL) {
        func_name = "localtime_r";
        goto fail;
    }
#endif

    // 成功返回 0
    return 0;

fail:
    // 失败时格式化错误信息,并设置异常类型为 PyExc_OSError,返回 -1
    PyErr_Format(PyExc_OSError, "Failed to use '%s' to convert "
                                "to a local time", func_name);
    return -1;
}

/*
 * Converts a datetimestruct in UTC to a datetimestruct in local time,
 * also returning the timezone offset applied. This function works for any year
 * > 1970 on all platforms and both 32 and 64 bits. If the year < 1970, then it
 * will fail on some platforms.
 *
 * Returns 0 on success, -1 on failure.
 */
static int
convert_datetimestruct_utc_to_local(npy_datetimestruct *out_dts_local,
                const npy_datetimestruct *dts_utc, int *out_timezone_offset)
{
    NPY_TIME_T rawtime = 0, localrawtime;
    struct tm tm_;
    npy_int64 year_correction = 0;

    /* Make a copy of the input 'dts' to modify */
    // 复制输入的 dts 到 out_dts_local 进行修改
    *out_dts_local = *dts_utc;

    /*
     * For 32 bit NPY_TIME_T, the get_localtime() function does not work for
     * years later than 2038, see the comments above get_localtime(). So if the
     * year >= 2038, we instead call get_localtime() for the year 2036 or 2037
     * (depending on the leap year) which must work and at the end we add the
     * 'year_correction' back.
     */
    // 对于 32 位 NPY_TIME_T,get_localtime() 函数无法处理 2038 年之后的年份
    // 如果年份大于等于 2038,则调整年份和 year_correction
    if (sizeof(NPY_TIME_T) == 4 && out_dts_local->year >= 2038) {
        if (is_leapyear(out_dts_local->year)) {
            /* 2036 is a leap year */
            year_correction = out_dts_local->year - 2036;
            out_dts_local->year -= year_correction; /* = 2036 */
        }
        else {
            /* 2037 is not a leap year */
            year_correction = out_dts_local->year - 2037;
            out_dts_local->year -= year_correction; /* = 2037 */
        }
    }

    /*
     * Convert everything in 'dts' to a time_t, to minutes precision.
     * This is POSIX time, which skips leap-seconds, but because
     * we drop the seconds value from the npy_datetimestruct, everything
     * is ok for this operation.
     */
    // 将 dts 中的所有内容转换为时间戳 rawtime,精确到分钟
    rawtime = (NPY_TIME_T)get_datetimestruct_days(out_dts_local) * 24 * 60 * 60;
    rawtime += dts_utc->hour * 60 * 60;
    rawtime += dts_utc->min * 60;

    /* localtime converts a 'time_t' into a local 'struct tm' */
    // 使用 localtime 将 time_t 转换为本地时间结构体 tm_
    if (get_localtime(&rawtime, &tm_) < 0) {
        /* This should only fail if year < 1970 on some platforms. */
        // 如果失败,通常是因为年份小于 1970 在某些平台上
        return -1;
    }

    /* Copy back all the values except seconds */
    // 复制除了秒数之外的所有值回 out_dts_local
    out_dts_local->min = tm_.tm_min;
    out_dts_local->hour = tm_.tm_hour;
    out_dts_local->day = tm_.tm_mday;
    out_dts_local->month = tm_.tm_mon + 1;
    out_dts_local->year = tm_.tm_year + 1900;

    /* Extract the timezone offset that was applied */
    // 计算应用的时区偏移量
    rawtime /= 60;
    localrawtime = (NPY_TIME_T)get_datetimestruct_days(out_dts_local) * 24 * 60;
    localrawtime += out_dts_local->hour * 60;
    localrawtime += out_dts_local->min;

    *out_timezone_offset = localrawtime - rawtime;

    /* Reapply the year 2038 year correction */
    // 重新应用年份修正值 2038
    # 将 out_dts_local 指针所指向的结构体的年份字段增加 year_correction 的值
    out_dts_local->year += year_correction;
    
    # 返回整数值 0,表示函数执行成功
    return 0;
/*NUMPY_API
 *
 * Parses (almost) standard ISO 8601 date strings. The differences are:
 *
 * + The date "20100312" is parsed as the year 20100312, not as
 *   equivalent to "2010-03-12". The '-' in the dates are not optional.
 * + Only seconds may have a decimal point, with up to 18 digits after it
 *   (maximum attoseconds precision).
 * + Either a 'T' as in ISO 8601 or a ' ' may be used to separate
 *   the date and the time. Both are treated equivalently.
 * + Doesn't (yet) handle the "YYYY-DDD" or "YYYY-Www" formats.
 * + Doesn't handle leap seconds (seconds value has 60 in these cases).
 * + Doesn't handle 24:00:00 as synonym for midnight (00:00:00) tomorrow
 * + Accepts special values "NaT" (not a time), "Today", (current
 *   day according to local time) and "Now" (current time in UTC).
 *
 * 'str' must be a NULL-terminated string, and 'len' must be its length.
 * 'unit' should contain -1 if the unit is unknown, or the unit
 *      which will be used if it is.
 * 'casting' controls how the detected unit from the string is allowed
 *           to be cast to the 'unit' parameter.
 *
 * 'out' gets filled with the parsed date-time.
 * 'out_bestunit' gives a suggested unit based on the amount of
 *      resolution provided in the string, or -1 for NaT.
 * 'out_special' gets set to 1 if the parsed time was 'today',
 *      'now', or ''/'NaT'. For 'today', the unit recommended is
 *      'D', for 'now', the unit recommended is 's', and for 'NaT'
 *      the unit recommended is 'Y'.
 *
 * Returns 0 on success, -1 on failure.
 */
NPY_NO_EXPORT int
NpyDatetime_ParseISO8601Datetime(
        char const *str, Py_ssize_t len,
        NPY_DATETIMEUNIT unit,
        NPY_CASTING casting,
        npy_datetimestruct *out,
        NPY_DATETIMEUNIT *out_bestunit,
        npy_bool *out_special)
{
    int year_leap = 0;
    int i, numdigits;
    char const *substr;
    Py_ssize_t sublen;
    NPY_DATETIMEUNIT bestunit;

    /* Initialize the output to all zeros */
    memset(out, 0, sizeof(npy_datetimestruct));
    out->month = 1;
    out->day = 1;

    /*
     * Convert the empty string and case-variants of "NaT" to not-a-time.
     * Tried to use PyOS_stricmp, but that function appears to be broken,
     * not even matching the strcmp function signature as it should.
     */
    if (len <= 0 || (len == 3 &&
                        tolower(str[0]) == 'n' &&
                        tolower(str[1]) == 'a' &&
                        tolower(str[2]) == 't')) {
        // 将输出年份设置为不是时间(NPY_DATETIME_NAT)
        out->year = NPY_DATETIME_NAT;

        /*
         * Indicate that this was a special value, and
         * recommend generic units.
         */
        if (out_bestunit != NULL) {
            // 建议使用通用单位
            *out_bestunit = NPY_FR_GENERIC;
        }
        if (out_special != NULL) {
            // 标记为特殊值
            *out_special = 1;
        }

        // 返回成功
        return 0;
    }
    # 如果时间单位是通用单位(NPY_FR_GENERIC)
    if (unit == NPY_FR_GENERIC) {
        # 设置一个错误字符串,指示无法创建除 NaT 外的 NumPy datetime 对象
        PyErr_SetString(PyExc_ValueError,
                    "Cannot create a NumPy datetime other than NaT "
                    "with generic units");
        # 返回错误代码
        return -1;
    }

    /*
     * 字符串 "today" 表示获取当前本地时间的日期,并将其转换为日期表示。
     * 如果强制将此日期表示转换为时间单位,它将是 UTC 时间的午夜。
     * 这可能有点奇怪,但是这样做是为了确保 'datetime64[D]' 类型产生您期望的日期,
     * 而不是根据当前时间和时区切换到相邻的日期。
     */
    # 如果字符串长度为5且全小写,且依次是 'today'
    if (len == 5 && tolower(str[0]) == 't' &&
                    tolower(str[1]) == 'o' &&
                    tolower(str[2]) == 'd' &&
                    tolower(str[3]) == 'a' &&
                    tolower(str[4]) == 'y') {
        # 初始化变量 rawtime 和 tm_
        NPY_TIME_T rawtime = 0;
        struct tm tm_;

        # 获取当前时间
        time(&rawtime);
        # 获取本地时间
        if (get_localtime(&rawtime, &tm_) < 0) {
            return -1;
        }
        # 将日期分量分配给输出结构体的年、月、日字段
        out->year = tm_.tm_year + 1900;
        out->month = tm_.tm_mon + 1;
        out->day = tm_.tm_mday;

        # 将时间单位设为 'D'(天)
        bestunit = NPY_FR_D;

        /*
         * 表明这是一个特殊值,并且是一个日期(单位为 'D')。
         */
        # 如果 out_bestunit 不为空,则将 bestunit 赋值给 out_bestunit
        if (out_bestunit != NULL) {
            *out_bestunit = bestunit;
        }
        # 如果 out_special 不为空,则将其设为1,表示是特殊值
        if (out_special != NULL) {
            *out_special = 1;
        }

        /* 检查类型转换规则 */
        # 如果单位不是错误状态,并且无法按照指定的转换规则将 bestunit 转换为 unit
        if (unit != NPY_FR_ERROR &&
                !can_cast_datetime64_units(bestunit, unit, casting)) {
            # 抛出类型错误,说明无法将字符串 str 解析为单位 'unit' 的日期
            PyErr_Format(PyExc_TypeError, "Cannot parse \"%s\" as unit "
                         "'%s' using casting rule %s",
                         str, _datetime_strings[unit],
                         npy_casting_to_string(casting));
            return -1;
        }

        # 返回成功代码
        return 0;
    }

    /* 字符串 "now" 表示当前的 UTC 时间 */
    // 检查字符串长度是否为3,并且前三个字符转换为小写后是否为 "now"
    if (len == 3 && tolower(str[0]) == 'n' &&
                    tolower(str[1]) == 'o' &&
                    tolower(str[2]) == 'w') {
        NPY_TIME_T rawtime = 0; // 初始化 rawtime 为 0
        PyArray_DatetimeMetaData meta; // 创建 PyArray_DatetimeMetaData 结构体变量 meta

        time(&rawtime); // 获取当前时间戳,并存储在 rawtime 中

        /* Set up a dummy metadata for the conversion */
        meta.base = NPY_FR_s; // 设置 meta 结构体的基础时间单位为秒
        meta.num = 1; // 设置 meta 结构体的数量为1

        bestunit = NPY_FR_s; // 设置最佳单位为秒

        /*
         * Indicate that this was a special value, and
         * use 's' because the time() function has resolution
         * seconds.
         */
        // 如果 out_bestunit 不为空,将 bestunit 赋值给它
        if (out_bestunit != NULL) {
            *out_bestunit = bestunit;
        }
        // 如果 out_special 不为空,将 1 赋值给它,表示这是一个特殊值
        if (out_special != NULL) {
            *out_special = 1;
        }

        /* Check the casting rule */
        // 检查转换规则是否允许将 bestunit 转换为 unit
        if (unit != NPY_FR_ERROR &&
                !can_cast_datetime64_units(bestunit, unit, casting)) {
            // 如果不允许,则设置错误并返回 -1
            PyErr_Format(PyExc_TypeError, "Cannot parse \"%s\" as unit "
                         "'%s' using casting rule %s",
                         str, _datetime_strings[unit],
                         npy_casting_to_string(casting));
            return -1;
        }

        // 调用函数将时间数据转换为结构体形式,并返回结果
        return NpyDatetime_ConvertDatetime64ToDatetimeStruct(&meta, rawtime, out);
    }

    /* Anything else isn't a special value */
    // 如果不是 "now",则不是特殊值,将 out_special 设为 0
    if (out_special != NULL) {
        *out_special = 0;
    }

    substr = str; // 设置 substr 指向字符串起始处
    sublen = len; // 设置 sublen 为字符串长度

    /* Skip leading whitespace */
    // 跳过开头的空白字符
    while (sublen > 0 && isspace(*substr)) {
        ++substr;
        --sublen;
    }

    /* Leading '-' sign for negative year */
    // 处理负数年份的前导 '-' 符号
    if (*substr == '-' || *substr == '+') {
        ++substr;
        --sublen;
    }

    // 如果长度为 0,则跳到解析错误处
    if (sublen == 0) {
        goto parse_error;
    }

    /* PARSE THE YEAR (digits until the '-' character) */
    // 解析年份(直到遇到 '-' 字符)
    out->year = 0;
    while (sublen > 0 && isdigit(*substr)) {
        out->year = 10 * out->year + (*substr - '0');
        ++substr;
        --sublen;
    }

    /* Negate the year if necessary */
    // 如果是负数年份,将年份取反
    if (str[0] == '-') {
        out->year = -out->year;
    }
    /* Check whether it's a leap-year */
    // 检查是否为闰年
    year_leap = is_leapyear(out->year);

    /* Next character must be a '-' or the end of the string */
    // 下一个字符必须是 '-' 或者字符串的结尾
    if (sublen == 0) {
        bestunit = NPY_FR_Y;
        goto finish;
    }
    else if (*substr == '-') {
        ++substr;
        --sublen;
    }
    else {
        goto parse_error;
    }

    /* Can't have a trailing '-' */
    // 不能以 '-' 结尾
    if (sublen == 0) {
        goto parse_error;
    }

    /* PARSE THE MONTH (2 digits) */
    // 解析月份(两位数字)
    if (sublen >= 2 && isdigit(substr[0]) && isdigit(substr[1])) {
        out->month = 10 * (substr[0] - '0') + (substr[1] - '0');

        // 检查月份是否在合法范围内
        if (out->month < 1 || out->month > 12) {
            PyErr_Format(PyExc_ValueError,
                        "Month out of range in datetime string \"%s\"", str);
            goto error;
        }
        substr += 2;
        sublen -= 2;
    }
    else {
        goto parse_error;
    }

    /* Next character must be a '-' or the end of the string */
    /* 如果子串长度为0 */
    if (sublen == 0) {
        /* 将最佳单位设置为 NPY_FR_M(月份) */
        bestunit = NPY_FR_M;
        /* 跳转到结束标签 */
        goto finish;
    }
    /* 如果子串的第一个字符是 '-' */
    else if (*substr == '-') {
        /* 移动指针到下一个字符 */
        ++substr;
        /* 减少子串长度 */
        --sublen;
    }
    /* 如果不满足上述两个条件,则说明解析错误 */
    else {
        /* 跳转到解析错误标签 */
        goto parse_error;
    }

    /* 不能以 '-' 结尾 */
    if (sublen == 0) {
        /* 跳转到解析错误标签 */
        goto parse_error;
    }

    /* 解析天数(2位数字) */
    if (sublen >= 2 && isdigit(substr[0]) && isdigit(substr[1])) {
        /* 计算天数 */
        out->day = 10 * (substr[0] - '0') + (substr[1] - '0');

        /* 检查天数范围是否有效 */
        if (out->day < 1 ||
                    out->day > _days_per_month_table[year_leap][out->month-1]) {
            /* 抛出异常,天数超出范围 */
            PyErr_Format(PyExc_ValueError,
                        "Day out of range in datetime string \"%s\"", str);
            /* 跳转到错误处理标签 */
            goto error;
        }
        /* 移动指针和减少子串长度 */
        substr += 2;
        sublen -= 2;
    }
    else {
        /* 跳转到解析错误标签 */
        goto parse_error;
    }

    /* 下一个字符必须是 'T', ' ', 或者字符串结束 */
    if (sublen == 0) {
        /* 将最佳单位设置为 NPY_FR_D(日) */
        bestunit = NPY_FR_D;
        /* 跳转到结束标签 */
        goto finish;
    }
    else if (*substr != 'T' && *substr != ' ') {
        /* 跳转到解析错误标签 */
        goto parse_error;
    }
    else {
        /* 移动指针到下一个字符 */
        ++substr;
        /* 减少子串长度 */
        --sublen;
    }

    /* 解析小时数(2位数字) */
    if (sublen >= 2 && isdigit(substr[0]) && isdigit(substr[1])) {
        /* 计算小时数 */
        out->hour = 10 * (substr[0] - '0') + (substr[1] - '0');

        /* 检查小时数范围是否有效 */
        if (out->hour >= 24) {
            /* 抛出异常,小时数超出范围 */
            PyErr_Format(PyExc_ValueError,
                        "Hours out of range in datetime string \"%s\"", str);
            /* 跳转到错误处理标签 */
            goto error;
        }
        /* 移动指针和减少子串长度 */
        substr += 2;
        sublen -= 2;
    }
    else {
        /* 跳转到解析错误标签 */
        goto parse_error;
    }

    /* 下一个字符必须是 ':' 或者字符串结束 */
    if (sublen > 0 && *substr == ':') {
        /* 移动指针到下一个字符 */
        ++substr;
        /* 减少子串长度 */
        --sublen;
    }
    else {
        /* 将最佳单位设置为 NPY_FR_h(小时) */
        bestunit = NPY_FR_h;
        /* 跳转到时区解析标签 */
        goto parse_timezone;
    }

    /* 不能以 ':' 结尾 */
    if (sublen == 0) {
        /* 跳转到解析错误标签 */
        goto parse_error;
    }

    /* 解析分钟数(2位数字) */
    if (sublen >= 2 && isdigit(substr[0]) && isdigit(substr[1])) {
        /* 计算分钟数 */
        out->min = 10 * (substr[0] - '0') + (substr[1] - '0');

        /* 检查分钟数范围是否有效 */
        if (out->min >= 60) {
            /* 抛出异常,分钟数超出范围 */
            PyErr_Format(PyExc_ValueError,
                        "Minutes out of range in datetime string \"%s\"", str);
            /* 跳转到错误处理标签 */
            goto error;
        }
        /* 移动指针和减少子串长度 */
        substr += 2;
        sublen -= 2;
    }
    else {
        /* 跳转到解析错误标签 */
        goto parse_error;
    }

    /* 下一个字符必须是 ':' 或者字符串结束 */
    if (sublen > 0 && *substr == ':') {
        /* 移动指针到下一个字符 */
        ++substr;
        /* 减少子串长度 */
        --sublen;
    }
    else {
        /* 将最佳单位设置为 NPY_FR_m(分钟) */
        bestunit = NPY_FR_m;
        /* 跳转到时区解析标签 */
        goto parse_timezone;
    }

    /* 不能以 ':' 结尾 */
    if (sublen == 0) {
        /* 跳转到解析错误标签 */
        goto parse_error;
    }

    /* 解析秒数(2位数字) */
    // 检查子字符串长度大于等于2且前两个字符均为数字
    if (sublen >= 2 && isdigit(substr[0]) && isdigit(substr[1])) {
        // 将前两个字符解析为秒数
        out->sec = 10 * (substr[0] - '0') + (substr[1] - '0');

        // 如果秒数超过60,则抛出异常并跳转到错误处理
        if (out->sec >= 60) {
            PyErr_Format(PyExc_ValueError,
                        "Seconds out of range in datetime string \"%s\"", str);
            goto error;
        }
        // 更新子字符串和长度以排除已解析的部分
        substr += 2;
        sublen -= 2;
    }
    else {
        // 如果前两个字符不是数字,则跳转到解析错误处理
        goto parse_error;
    }

    /* 下一个字符可能是'.',表示有小数秒 */
    if (sublen > 0 && *substr == '.') {
        ++substr;
        --sublen;
    }
    else {
        // 如果没有小数秒部分,则设定时间单位为秒,并跳转到解析时区部分
        bestunit = NPY_FR_s;
        goto parse_timezone;
    }

    /* 解析微秒部分(06位数字) */
    numdigits = 0;
    for (i = 0; i < 6; ++i) {
        // 微秒数乘以10,加上下一个字符的数字值(如果存在)
        out->us *= 10;
        if (sublen > 0  && isdigit(*substr)) {
            out->us += (*substr - '0');
            ++substr;
            --sublen;
            ++numdigits;
        }
    }

    // 如果没有剩余字符或下一个字符不是数字
    if (sublen == 0 || !isdigit(*substr)) {
        // 根据解析的数字位数设定最适合的时间单位
        if (numdigits > 3) {
            bestunit = NPY_FR_us;
        }
        else {
            bestunit = NPY_FR_ms;
        }
        // 跳转到解析时区部分
        goto parse_timezone;
    }

    /* 解析皮秒部分(06位数字) */
    numdigits = 0;
    for (i = 0; i < 6; ++i) {
        // 皮秒数乘以10,加上下一个字符的数字值(如果存在)
        out->ps *= 10;
        if (sublen > 0 && isdigit(*substr)) {
            out->ps += (*substr - '0');
            ++substr;
            --sublen;
            ++numdigits;
        }
    }

    // 如果没有剩余字符或下一个字符不是数字
    if (sublen == 0 || !isdigit(*substr)) {
        // 根据解析的数字位数设定最适合的时间单位
        if (numdigits > 3) {
            bestunit = NPY_FR_ps;
        }
        else {
            bestunit = NPY_FR_ns;
        }
        // 跳转到解析时区部分
        goto parse_timezone;
    }

    /* 解析阿托秒部分(06位数字) */
    numdigits = 0;
    for (i = 0; i < 6; ++i) {
        // 阿托秒数乘以10,加上下一个字符的数字值(如果存在)
        out->as *= 10;
        if (sublen > 0 && isdigit(*substr)) {
            out->as += (*substr - '0');
            ++substr;
            --sublen;
            ++numdigits;
        }
    }

    // 根据解析的数字位数设定最适合的时间单位
    if (numdigits > 3) {
        bestunit = NPY_FR_as;
    }
    else {
        bestunit = NPY_FR_fs;
    }
    // 跳转到解析时区部分
    ```
// 如果子串长度为0,跳转到结束标记
if (sublen == 0) {
    goto finish;
}
else {
    // 清除之前的错误状态
    PyErr_Clear();
    // 发出警告:对于 np.datetime64,没有显式的时区表示
    if (PyErr_WarnEx(PyExc_UserWarning,
        "no explicit representation of timezones available for np.datetime64",
        1) < 0) {
            return -1;
        }
}

// UTC 时间标识符处理
if (*substr == 'Z') {
    // 如果子串只有一个字符 'Z',跳转到结束标记
    if (sublen == 1) {
        goto finish;
    }
    else {
        // 移动子串指针和减少子串长度
        ++substr;
        --sublen;
    }
}
// 处理时区偏移量
else if (*substr == '-' || *substr == '+') {
    int offset_neg = 0, offset_hour = 0, offset_minute = 0;

    // 判断偏移量正负
    if (*substr == '-') {
        offset_neg = 1;
    }
    ++substr;
    --sublen;

    // 处理小时偏移量
    if (sublen >= 2 && isdigit(substr[0]) && isdigit(substr[1])) {
        offset_hour = 10 * (substr[0] - '0') + (substr[1] - '0');
        substr += 2;
        sublen -= 2;
        // 如果小时偏移量超出范围,报错
        if (offset_hour >= 24) {
            PyErr_Format(PyExc_ValueError,
                        "Timezone hours offset out of range "
                        "in datetime string \"%s\"", str);
            goto error;
        }
    }
    else {
        goto parse_error;
    }

    // 处理分钟偏移量(可选部分)
    if (sublen > 0) {
        // 可选的 ':' 分隔符
        if (*substr == ':') {
            ++substr;
            --sublen;
        }

        // 处理分钟偏移量(在字符串末尾)
        if (sublen >= 2 && isdigit(substr[0]) && isdigit(substr[1])) {
            offset_minute = 10 * (substr[0] - '0') + (substr[1] - '0');
            substr += 2;
            sublen -= 2;
            // 如果分钟偏移量超出范围,报错
            if (offset_minute >= 60) {
                PyErr_Format(PyExc_ValueError,
                            "Timezone minutes offset out of range "
                            "in datetime string \"%s\"", str);
                goto error;
            }
        }
        else {
            goto parse_error;
        }
    }

    // 应用时间偏移量
    if (offset_neg) {
        offset_hour = -offset_hour;
        offset_minute = -offset_minute;
    }
    // 将偏移量分钟数添加到日期时间结构
    add_minutes_to_datetimestruct(out, -60 * offset_hour - offset_minute);
}

// 跳过尾部空白字符
while (sublen > 0 && isspace(*substr)) {
    ++substr;
    --sublen;
}

// 如果子串长度不为0,报错
if (sublen != 0) {
    goto parse_error;
}

// 达到正常解析结束标记
finish:
// 如果 out_bestunit 不为 NULL,则将 bestunit 赋给 *out_bestunit
if (out_bestunit != NULL) {
    *out_bestunit = bestunit;
}

// 检查转换规则
    # 检查单元是否不是错误标志,并且无法将 datetime64 的最佳单位转换为指定的单位
    if (unit != NPY_FR_ERROR &&
            !can_cast_datetime64_units(bestunit, unit, casting)) {
        # 抛出类型错误异常,指示无法使用指定的类型转换规则将字符串解析为指定单位的日期时间单位
        PyErr_Format(PyExc_TypeError, "Cannot parse \"%s\" as unit "
                     "'%s' using casting rule %s",
                     str, _datetime_strings[unit],
                     npy_casting_to_string(casting));
        # 返回 -1 表示失败
        return -1;
    }

    # 如果能够成功解析,返回 0 表示成功
    return 0;
parse_error:
    PyErr_Format(PyExc_ValueError,
            "Error parsing datetime string \"%s\" at position %zd",
            str, substr - str);
    return -1;


// 在解析日期时间字符串时发生错误,格式化错误信息并返回 -1
parse_error:
    PyErr_Format(PyExc_ValueError,
            "Error parsing datetime string \"%s\" at position %zd",
            str, substr - str);
    return -1;



error:
    return -1;
}


// 返回 -1 表示发生错误
error:
    return -1;
}



/*NUMPY_API
 *
 * Provides a string length to use for converting datetime
 * objects with the given local and unit settings.
 */
NPY_NO_EXPORT int
NpyDatetime_GetDatetimeISO8601StrLen(int local, NPY_DATETIMEUNIT base)
{
    int len = 0;

    switch (base) {
        case NPY_FR_ERROR:
            /* If no unit is provided, return the maximum length */
            return NPY_DATETIME_MAX_ISO8601_STRLEN;
        case NPY_FR_GENERIC:
            /* Generic units can only be used to represent NaT */
            return 4;
        case NPY_FR_as:
            len += 3;  /* "###" */
        case NPY_FR_fs:
            len += 3;  /* "###" */
        case NPY_FR_ps:
            len += 3;  /* "###" */
        case NPY_FR_ns:
            len += 3;  /* "###" */
        case NPY_FR_us:
            len += 3;  /* "###" */
        case NPY_FR_ms:
            len += 4;  /* ".###" */
        case NPY_FR_s:
            len += 3;  /* ":##" */
        case NPY_FR_m:
            len += 3;  /* ":##" */
        case NPY_FR_h:
            len += 3;  /* "T##" */
        case NPY_FR_D:
        case NPY_FR_W:
            len += 3;  /* "-##" */
        case NPY_FR_M:
            len += 3;  /* "-##" */
        case NPY_FR_Y:
            len += 21; /* 64-bit year */
            break;
    }

    if (base >= NPY_FR_h) {
        if (local) {
            len += 5;  /* "+####" or "-####" */
        }
        else {
            len += 1;  /* "Z" */
        }
    }

    len += 1; /* NULL terminator */

    return len;
}


/*NUMPY_API
 *
 * 提供用于转换日期时间对象的字符串长度,根据给定的本地和单位设置。
 */
NPY_NO_EXPORT int
NpyDatetime_GetDatetimeISO8601StrLen(int local, NPY_DATETIMEUNIT base)
{
    int len = 0;

    switch (base) {
        case NPY_FR_ERROR:
            /* 如果没有提供单位,则返回最大长度 */
            return NPY_DATETIME_MAX_ISO8601_STRLEN;
        case NPY_FR_GENERIC:
            /* 通用单位只能用于表示 NaT */
            return 4;
        case NPY_FR_as:
            len += 3;  /* "###" */
        case NPY_FR_fs:
            len += 3;  /* "###" */
        case NPY_FR_ps:
            len += 3;  /* "###" */
        case NPY_FR_ns:
            len += 3;  /* "###" */
        case NPY_FR_us:
            len += 3;  /* "###" */
        case NPY_FR_ms:
            len += 4;  /* ".###" */
        case NPY_FR_s:
            len += 3;  /* ":##" */
        case NPY_FR_m:
            len += 3;  /* ":##" */
        case NPY_FR_h:
            len += 3;  /* "T##" */
        case NPY_FR_D:
        case NPY_FR_W:
            len += 3;  /* "-##" */
        case NPY_FR_M:
            len += 3;  /* "-##" */
        case NPY_FR_Y:
            len += 21; /* 64-bit year */
            break;
    }

    if (base >= NPY_FR_h) {
        if (local) {
            len += 5;  /* "+####" or "-####" */
        }
        else {
            len += 1;  /* "Z" */
        }
    }

    len += 1; /* 空字符终止符 */

    return len;
}



/*
 * Finds the largest unit whose value is nonzero, and for which
 * the remainder for the rest of the units is zero.
 */
static NPY_DATETIMEUNIT
lossless_unit_from_datetimestruct(npy_datetimestruct *dts)
{
    if (dts->as % 1000 != 0) {
        return NPY_FR_as;
    }
    else if (dts->as != 0) {
        return NPY_FR_fs;
    }
    else if (dts->ps % 1000 != 0) {
        return NPY_FR_ps;
    }
    else if (dts->ps != 0) {
        return NPY_FR_ns;
    }
    else if (dts->us % 1000 != 0) {
        return NPY_FR_us;
    }
    else if (dts->us != 0) {
        return NPY_FR_ms;
    }
    else if (dts->sec != 0) {
        return NPY_FR_s;
    }
    else if (dts->min != 0) {
        return NPY_FR_m;
    }
    else if (dts->hour != 0) {
        return NPY_FR_h;
    }
    else if (dts->day != 1) {
        return NPY_FR_D;
    }
    else if (dts->month != 1) {
        return NPY_FR_M;
    }
    else {
        return NPY_FR_Y;
    }
}


/*
 * 找到数值非零的最大单位,并且其余单位的余数为零。
 */
static NPY_DATETIMEUNIT
lossless_unit_from_datetimestruct(npy_datetimestruct *dts)
{
    if (dts->as % 1000 != 0) {
        return NPY_FR_as;
    }
    else if (dts->as != 0) {
        return NPY_FR_fs;
    }
    else if (dts->ps % 1000 != 0) {
        return NPY_FR_ps;
    }
    else if (dts->ps != 0) {
        return NPY_FR_ns;
    }
    else if (dts->us % 1000 != 0) {
        return NPY_FR_us;
    }
    else if (dts->us != 0) {
        return NPY_FR_ms;
    }
    else if (dts->sec != 0) {
        return NPY_FR_s;
    }
    else if (dts->min != 0) {
        return NPY_FR_m;
    }
    else if (dts->hour != 0) {
        return NPY_FR_h;
    }
    else if (dts->day != 1) {
        return NPY_FR_D;
    }
    else if (dts->month != 1) {
        return NPY_FR_M;
    }
    else {
        return NPY_FR_Y;
    }
}
/*
 * Converts an npy_datetimestruct to an (almost) ISO 8601
 * NULL-terminated string. If the string fits in the space exactly,
 * it leaves out the NULL terminator and returns success.
 *
 * The differences from ISO 8601 are the 'NaT' string, and
 * the number of year digits is >= 4 instead of strictly 4.
 *
 * If 'local' is non-zero, it produces a string in local time with
 * a +-#### timezone offset. If 'local' is zero and 'utc' is non-zero,
 * produce a string ending with 'Z' to denote UTC. By default, no time
 * zone information is attached.
 *
 * 'base' restricts the output to that unit. Set 'base' to
 * -1 to auto-detect a base after which all the values are zero.
 *
 * 'tzoffset' is used if 'local' is enabled, and 'tzoffset' is
 * set to a value other than -1. This is a manual override for
 * the local time zone to use, as an offset in minutes.
 *
 * 'casting' controls whether data loss is allowed by truncating
 * the data to a coarser unit. This interacts with 'local', slightly,
 * in order to form a date unit string as a local time, the casting
 * must be unsafe.
 *
 * Returns 0 on success, -1 on failure (for example if the output
 * string was too short).
 */
NPY_NO_EXPORT int
NpyDatetime_MakeISO8601Datetime(
        npy_datetimestruct *dts, char *outstr, npy_intp outlen,
        int local, int utc, NPY_DATETIMEUNIT base, int tzoffset,
        NPY_CASTING casting)
{
    npy_datetimestruct dts_local;
    int timezone_offset = 0;

    char *substr = outstr; // 初始化字符串指针
    npy_intp sublen = outlen; // 初始化字符串长度

    /* Handle NaT, and treat a datetime with generic units as NaT */
    if (dts->year == NPY_DATETIME_NAT || base == NPY_FR_GENERIC) {
        if (outlen < 3) { // 如果输出空间不足
            goto string_too_short; // 转到字符串太短的错误处理
        }
        outstr[0] = 'N'; // 设置输出字符串为 NaT
        outstr[1] = 'a';
        outstr[2] = 'T';
        if (outlen > 3) {
            outstr[3] = '\0'; // 添加字符串结束符
        }

        return 0; // 返回成功
    }

    /*
     * Only do local time within a reasonable year range. The years
     * earlier than 1970 are not made local, because the Windows API
     * raises an error when they are attempted (see the comments above the
     * get_localtime() function). For consistency, this
     * restriction is applied to all platforms.
     *
     * Note that this only affects how the datetime becomes a string.
     * The result is still completely unambiguous, it only means
     * that datetimes outside this range will not include a time zone
     * when they are printed.
     */
    if ((dts->year < 1970 || dts->year >= 10000) && tzoffset == -1) {
        local = 0; // 如果年份早于1970或者大于等于10000且没有指定时区偏移,则不使用本地时间
    }

    /* Automatically detect a good unit */
    # 如果基础单位为错误,根据日期时间结构生成最适合的单位
    if (base == NPY_FR_ERROR) {
        base = lossless_unit_from_datetimestruct(dts);
        
        /*
         * 如果有时区信息,则至少使用分钟精度,
         * 默认情况下不会将小时和分钟分开
         */
        if ((base < NPY_FR_m && local) || base == NPY_FR_h) {
            base = NPY_FR_m;
        }
        /* 默认情况下不会分开日期 */
        else if (base < NPY_FR_D) {
            base = NPY_FR_D;
        }
    }
    
    /*
     * 以与天相同的精度打印周。
     *
     * TODO: 如果周的起始日期是星期一,可以使用 YYYY-Www 格式打印周
     */
    else if (base == NPY_FR_W) {
        base = NPY_FR_D;
    }

    /* 使用 C API 将时间从 UTC 转换为本地时间 */
    if (local && tzoffset == -1) {
        if (convert_datetimestruct_utc_to_local(&dts_local, dts,
                                                &timezone_offset) < 0) {
            return -1;
        }

        /* 将 dts 指向本地时间,而不是 UTC 时间 */
        dts = &dts_local;
    }
    /* 使用手动提供的时区偏移量 */
    else if (local) {
        /* 创建 dts 的副本,以便进行修改 */
        dts_local = *dts;
        dts = &dts_local;

        /* 设置并应用所需的时区偏移量 */
        timezone_offset = tzoffset;
        add_minutes_to_datetimestruct(dts, timezone_offset);
    }

    /*
     * 现在 datetimestruct 数据已经是最终形式,用于字符串表示,
     * 因此确保根据转换规则进行类型转换。
     */
    if (casting != NPY_UNSAFE_CASTING) {
        /* 生成本地时间的日期作为字符串总是 'unsafe' */
        if (base <= NPY_FR_D && local) {
            PyErr_SetString(PyExc_TypeError, "Cannot create a local "
                        "timezone-based date string from a NumPy "
                        "datetime without forcing 'unsafe' casting");
            return -1;
        }
        /* 只有 'unsafe''same_kind' 允许数据丢失 */
        else {
            NPY_DATETIMEUNIT unitprec;

            unitprec = lossless_unit_from_datetimestruct(dts);
            if (casting != NPY_SAME_KIND_CASTING && unitprec > base) {
                PyErr_Format(PyExc_TypeError, "Cannot create a "
                            "string with unit precision '%s' "
                            "from the NumPy datetime, which has data at "
                            "unit precision '%s', "
                            "requires 'unsafe' or 'same_kind' casting",
                             _datetime_strings[base],
                             _datetime_strings[unitprec]);
                return -1;
            }
        }
    }

    /* 年 */
    /*
     * 不能使用 PyOS_snprintf,因为它总是在末尾生成 '\0' 字符,
     * 而 NumPy 字符串类型允许数据一直到缓冲区的末尾。
     */
#ifdef _WIN32
    // 在 Windows 平台下使用 _snprintf 函数格式化年份到 substr 中
    tmplen = _snprintf(substr, sublen, "%04" NPY_INT64_FMT, dts->year);
#else
    // 在非 Windows 平台下使用 snprintf 函数格式化年份到 substr 中
    tmplen = snprintf(substr, sublen, "%04" NPY_INT64_FMT, dts->year);
#endif

    /* 如果字符串空间不足或者没有空间放置 NULL 终止符 */
    if (tmplen < 0 || tmplen > sublen) {
        // 如果出现空间不足的情况,则跳转到标签 string_too_short 处处理
        goto string_too_short;
    }

    // 更新 substr 指针位置,减少剩余空间长度
    substr += tmplen;
    sublen -= tmplen;

    /* 如果时间单位为年,则直接结束 */
    if (base == NPY_FR_Y) {
        // 如果剩余空间足够,添加字符串结尾符 '\0'
        if (sublen > 0) {
            *substr = '\0';
        }
        // 返回成功状态
        return 0;
    }

    /* 月份 */
    if (sublen < 1 ) {
        // 如果剩余空间不足,则跳转到标签 string_too_short 处处理
        goto string_too_short;
    }
    // 在 substr 中添加 '-' 字符
    substr[0] = '-';
    if (sublen < 2 ) {
        // 如果剩余空间不足,则跳转到标签 string_too_short 处处理
        goto string_too_short;
    }
    // 在 substr 中添加月份的十位数字
    substr[1] = (char)((dts->month / 10) + '0');
    if (sublen < 3 ) {
        // 如果剩余空间不足,则跳转到标签 string_too_short 处处理
        goto string_too_short;
    }
    // 在 substr 中添加月份的个位数字
    substr[2] = (char)((dts->month % 10) + '0');
    // 更新 substr 指针位置,减少剩余空间长度
    substr += 3;
    sublen -= 3;

    /* 如果时间单位为月,则直接结束 */
    if (base == NPY_FR_M) {
        // 如果剩余空间足够,添加字符串结尾符 '\0'
        if (sublen > 0) {
            *substr = '\0';
        }
        // 返回成功状态
        return 0;
    }

    /* 天数 */
    if (sublen < 1 ) {
        // 如果剩余空间不足,则跳转到标签 string_too_short 处处理
        goto string_too_short;
    }
    // 在 substr 中添加 '-' 字符
    substr[0] = '-';
    if (sublen < 2 ) {
        // 如果剩余空间不足,则跳转到标签 string_too_short 处处理
        goto string_too_short;
    }
    // 在 substr 中添加天数的十位数字
    substr[1] = (char)((dts->day / 10) + '0');
    if (sublen < 3 ) {
        // 如果剩余空间不足,则跳转到标签 string_too_short 处处理
        goto string_too_short;
    }
    // 在 substr 中添加天数的个位数字
    substr[2] = (char)((dts->day % 10) + '0');
    // 更新 substr 指针位置,减少剩余空间长度
    substr += 3;
    sublen -= 3;

    /* 如果时间单位为天,则直接结束 */
    if (base == NPY_FR_D) {
        // 如果剩余空间足够,添加字符串结尾符 '\0'
        if (sublen > 0) {
            *substr = '\0';
        }
        // 返回成功状态
        return 0;
    }

    /* 小时 */
    if (sublen < 1 ) {
        // 如果剩余空间不足,则跳转到标签 string_too_short 处处理
        goto string_too_short;
    }
    // 在 substr 中添加 'T' 字符,表示时间的开始
    substr[0] = 'T';
    if (sublen < 2 ) {
        // 如果剩余空间不足,则跳转到标签 string_too_short 处处理
        goto string_too_short;
    }
    // 在 substr 中添加小时的十位数字
    substr[1] = (char)((dts->hour / 10) + '0');
    if (sublen < 3 ) {
        // 如果剩余空间不足,则跳转到标签 string_too_short 处处理
        goto string_too_short;
    }
    // 在 substr 中添加小时的个位数字
    substr[2] = (char)((dts->hour % 10) + '0');
    // 更新 substr 指针位置,减少剩余空间长度
    substr += 3;
    sublen -= 3;

    /* 如果时间单位为小时,则跳转到标签 add_time_zone 处处理 */
    if (base == NPY_FR_h) {
        goto add_time_zone;
    }

    /* 分钟 */
    if (sublen < 1 ) {
        // 如果剩余空间不足,则跳转到标签 string_too_short 处处理
        goto string_too_short;
    }
    // 在 substr 中添加 ':' 字符,表示小时和分钟的分隔符
    substr[0] = ':';
    if (sublen < 2 ) {
        // 如果剩余空间不足,则跳转到标签 string_too_short 处处理
        goto string_too_short;
    }
    // 在 substr 中添加分钟的十位数字
    substr[1] = (char)((dts->min / 10) + '0');
    if (sublen < 3 ) {
        // 如果剩余空间不足,则跳转到标签 string_too_short 处处理
        goto string_too_short;
    }
    // 在 substr 中添加分钟的个位数字
    substr[2] = (char)((dts->min % 10) + '0');
    // 更新 substr 指针位置,减少剩余空间长度
    substr += 3;
    sublen -= 3;

    /* 如果时间单位为分钟,则跳转到标签 add_time_zone 处处理 */
    if (base == NPY_FR_m) {
        goto add_time_zone;
    }

    /* 秒数 */
    if (sublen < 1 ) {
        // 如果剩余空间不足,则跳转到标签 string_too_short 处处理
        goto string_too_short;
    }
    // 在 substr 中添加 ':' 字符,表示分钟和秒数的分隔符
    substr[0] = ':';
    if (sublen < 2 ) {
        // 如果剩余空间不足,则跳转到标签 string_too_short 处处理
        goto string_too_short;
    }
    // 在 substr 中添加秒数的十位数字
    substr[1] = (char)((dts->sec / 10) + '0');
    if (sublen < 3 ) {
        // 如果剩余空间不足,则跳转到标签 string_too_short 处处理
        goto string_too_short;
    }
    // 在 substr 中添加秒数的个位数字
    substr[2] = (char)((dts->sec % 10) + '0');
    // 更新 substr 指针位置,减少剩余空间长度
    substr += 3;
    sublen -= 3;

    /* 如果时间单位为秒,则跳转到标签 add_time_zone 处处理 */
    if (base == NPY_FR_s) {
        goto add_time_zone;
    }

    /* 毫秒 */
    if (sublen < 1 ) {
        // 如果剩余空间不足,则跳转到标签 string_too_short 处处理
        goto string_too_short;
    }
    // 在 substr 中添加 '.' 字符,表示秒数和毫秒的分隔符
    substr[0] = '.';
    // 检查子字符串长度是否小于2,如果是则跳转到标签 string_too_short
    if (sublen < 2 ) {
        goto string_too_short;
    }
    // 将微秒部分的百万位数转换为字符存入 substr[1]
    substr[1] = (char)((dts->us / 100000) % 10 + '0');
    // 检查子字符串长度是否小于3,如果是则跳转到标签 string_too_short
    if (sublen < 3 ) {
        goto string_too_short;
    }
    // 将微秒部分的十万位数转换为字符存入 substr[2]
    substr[2] = (char)((dts->us / 10000) % 10 + '0');
    // 检查子字符串长度是否小于4,如果是则跳转到标签 string_too_short
    if (sublen < 4 ) {
        goto string_too_short;
    }
    // 将微秒部分的万位数到个位数转换为字符存入 substr[3],并更新 substr 和 sublen
    substr[3] = (char)((dts->us / 1000) % 10 + '0');
    substr += 4;
    sublen -= 4;

    /* 如果时间单位是毫秒,则跳转到标签 add_time_zone */
    if (base == NPY_FR_ms) {
        goto add_time_zone;
    }

    /* 微秒部分 */
    // 检查子字符串长度是否小于1,如果是则跳转到标签 string_too_short
    if (sublen < 1 ) {
        goto string_too_short;
    }
    // 将微秒部分的百位数转换为字符存入 substr[0]
    substr[0] = (char)((dts->us / 100) % 10 + '0');
    // 检查子字符串长度是否小于2,如果是则跳转到标签 string_too_short
    if (sublen < 2 ) {
        goto string_too_short;
    }
    // 将微秒部分的十位数转换为字符存入 substr[1]
    substr[1] = (char)((dts->us / 10) % 10 + '0');
    // 检查子字符串长度是否小于3,如果是则跳转到标签 string_too_short
    if (sublen < 3 ) {
        goto string_too_short;
    }
    // 将微秒部分的个位数转换为字符存入 substr[2],并更新 substr 和 sublen
    substr[2] = (char)(dts->us % 10 + '0');
    substr += 3;
    sublen -= 3;

    /* 如果时间单位是微秒,则跳转到标签 add_time_zone */
    if (base == NPY_FR_us) {
        goto add_time_zone;
    }

    /* 纳秒部分 */
    // 检查子字符串长度是否小于1,如果是则跳转到标签 string_too_short
    if (sublen < 1 ) {
        goto string_too_short;
    }
    // 将纳秒部分的十亿位数转换为字符存入 substr[0]
    substr[0] = (char)((dts->ps / 100000) % 10 + '0');
    // 检查子字符串长度是否小于2,如果是则跳转到标签 string_too_short
    if (sublen < 2 ) {
        goto string_too_short;
    }
    // 将纳秒部分的百万位数转换为字符存入 substr[1]
    substr[1] = (char)((dts->ps / 10000) % 10 + '0');
    // 检查子字符串长度是否小于3,如果是则跳转到标签 string_too_short
    if (sublen < 3 ) {
        goto string_too_short;
    }
    // 将纳秒部分的千位数转换为字符存入 substr[2],并更新 substr 和 sublen
    substr[2] = (char)((dts->ps / 1000) % 10 + '0');
    substr += 3;
    sublen -= 3;

    /* 如果时间单位是纳秒,则跳转到标签 add_time_zone */
    if (base == NPY_FR_ns) {
        goto add_time_zone;
    }

    /* 皮秒部分 */
    // 检查子字符串长度是否小于1,如果是则跳转到标签 string_too_short
    if (sublen < 1 ) {
        goto string_too_short;
    }
    // 将皮秒部分的十万亿位数转换为字符存入 substr[0]
    substr[0] = (char)((dts->ps / 100) % 10 + '0');
    // 检查子字符串长度是否小于2,如果是则跳转到标签 string_too_short
    if (sublen < 2 ) {
        goto string_too_short;
    }
    // 将皮秒部分的十亿位数转换为字符存入 substr[1]
    substr[1] = (char)((dts->ps / 10) % 10 + '0');
    // 检查子字符串长度是否小于3,如果是则跳转到标签 string_too_short
    if (sublen < 3 ) {
        goto string_too_short;
    }
    // 将皮秒部分的个位数转换为字符存入 substr[2],并更新 substr 和 sublen
    substr[2] = (char)(dts->ps % 10 + '0');
    substr += 3;
    sublen -= 3;

    /* 如果时间单位是皮秒,则跳转到标签 add_time_zone */
    if (base == NPY_FR_ps) {
        goto add_time_zone;
    }

    /* 飞秒部分 */
    // 检查子字符串长度是否小于1,如果是则跳转到标签 string_too_short
    if (sublen < 1 ) {
        goto string_too_short;
    }
    // 将飞秒部分的百万亿亿位数转换为字符存入 substr[0]
    substr[0] = (char)((dts->as / 100000) % 10 + '0');
    // 检查子字符串长度是否小于2,如果是则跳转到标签 string_too_short
    if (sublen < 2 ) {
        goto string_too_short;
    }
    // 将飞秒部分的十亿亿位数转换为字符存入 substr[1]
    substr[1] = (char)((dts->as / 10000) % 10 + '0');
    // 检查子字符串长度是否小于3,如果是则跳转到标签 string_too_short
    if (sublen < 3 ) {
        goto string_too_short;
    }
    // 将飞秒部分的亿位数转换为字符存入 substr[2],并更新 substr 和 sublen
    substr[2] = (char)((dts->as / 1000) % 10 + '0');
    substr += 3;
    sublen -= 3;

    /* 如果时间单位是飞秒,则跳转到标签 add_time_zone */
    if (base == NPY_FR_fs) {
        goto add_time_zone;
    }

    /* 阿托秒部分 */
    // 检查子字符串长度是否小于1,如果是则跳转到标签 string_too_short
    if (sublen < 1 ) {
        goto string_too_short;
    }
    // 将阿托秒部分的百亿亿位数转换为字符存入 substr[0]
    substr[0] = (char)((dts->as / 100) % 10 + '0');
    // 检查子字符串长度是否小于2,如果是则跳转到标签 string_too_short
    if (sublen < 2 ) {
        goto string_too_short;
    }
    // 将阿托秒部分的十亿亿位数转换为字符存入 substr[1]
    substr[1] = (char)((dts->as / 10) % 10 + '0');
    // 检查子字符串长度是否小于3,如果是则跳转到标签 string_too_short
    if (sublen < 3 ) {
        goto string_too_short;
    }
    // 将阿托秒部分的亿位数转换为字符存入 substr[2],并更新 substr
add_time_zone:
    if (local) {
        /* 添加正负号 */
        if (sublen < 1) {
            goto string_too_short;
        }
        /* 如果时区偏移小于0,添加负号 */
        if (timezone_offset < 0) {
            substr[0] = '-';
            timezone_offset = -timezone_offset;
        }
        else {
            /* 否则添加正号 */
            substr[0] = '+';
        }
        substr += 1;  // 指向下一个字符位置
        sublen -= 1;  // 剩余字符长度减1

        /* 添加时区偏移 */
        if (sublen < 1 ) {
            goto string_too_short;
        }
        /* 添加小时位 */
        substr[0] = (char)((timezone_offset / (10*60)) % 10 + '0');
        if (sublen < 2 ) {
            goto string_too_short;
        }
        /* 添加十位分钟 */
        substr[1] = (char)((timezone_offset / 60) % 10 + '0');
        if (sublen < 3 ) {
            goto string_too_short;
        }
        /* 添加个位分钟 */
        substr[2] = (char)(((timezone_offset % 60) / 10) % 10 + '0');
        if (sublen < 4 ) {
            goto string_too_short;
        }
        /* 添加个位秒 */
        substr[3] = (char)((timezone_offset % 60) % 10 + '0');
        substr += 4;  // 指向下一个字符位置
        sublen -= 4;  // 剩余字符长度减4
    }
    /* UTC "Zulu" 时间 */
    else if (utc) {
        if (sublen < 1) {
            goto string_too_short;
        }
        substr[0] = 'Z';  // 添加UTC标识符
        substr += 1;  // 指向下一个字符位置
        sublen -= 1;  // 剩余字符长度减1
    }

    /* 添加空字符终止符,并返回 */
    if (sublen > 0) {
        substr[0] = '\0';  // 添加空字符终止符
    }

    return 0;

string_too_short:
    PyErr_Format(PyExc_RuntimeError,
                "The string provided for NumPy ISO datetime formatting "
                "was too short, with length %"NPY_INTP_FMT,
                outlen);
    return -1;
}

/*
 * 这是 Python 中公开的 datetime_as_string 函数。
 */
NPY_NO_EXPORT PyObject *
array_datetime_as_string(PyObject *NPY_UNUSED(self), PyObject *args,
                                PyObject *kwds)
{
    PyObject *arr_in = NULL, *unit_in = NULL, *timezone_obj = NULL;
    NPY_DATETIMEUNIT unit;
    NPY_CASTING casting = NPY_SAME_KIND_CASTING;

    int local = 0;  // 本地时间标志
    int utc = 0;    // UTC时间标志
    PyArray_DatetimeMetaData *meta;
    int strsize;

    PyArrayObject *ret = NULL;

    NpyIter *iter = NULL;
    PyArrayObject *op[2] = {NULL, NULL};
    PyArray_Descr *op_dtypes[2] = {NULL, NULL};
    npy_uint32 flags, op_flags[2];

    static char *kwlist[] = {"arr", "unit", "timezone", "casting", NULL};

    if(!PyArg_ParseTupleAndKeywords(args, kwds,
                                "O|OOO&:datetime_as_string", kwlist,
                                &arr_in,
                                &unit_in,
                                &timezone_obj,
                                &PyArray_CastingConverter, &casting)) {
        return NULL;
    }

    /* 保留时区的引用供后续使用 */
    Py_XINCREF(timezone_obj);

    op[0] = (PyArrayObject *)PyArray_FROM_O(arr_in);
    if (op[0] == NULL) {
        goto fail;
    }
    /* 确保输入的类型为 NumPy datetime */
    if (PyArray_DESCR(op[0])->type_num != NPY_DATETIME) {
        PyErr_SetString(PyExc_TypeError,
                    "input must have type NumPy datetime");
        goto fail;
    }

    /* 获取 datetime 元数据 */
    meta = get_datetime_metadata_from_dtype(PyArray_DESCR(op[0]));
    # 从 op[0] 的数据类型描述符中获取日期时间元数据
    if (meta == NULL) {
        goto fail;
    }

    /* Use the metadata's unit for printing by default */
    # 默认情况下使用元数据的单位进行打印
    unit = meta->base;

    /* Parse the input unit if provided */
    # 如果提供了输入单位,则解析它
    if (unit_in != NULL && unit_in != Py_None) {
        PyObject *strobj;

        if (PyBytes_Check(unit_in)) {
            /* accept bytes input */
            # 接受字节输入
            PyObject *obj_str = PyUnicode_FromEncodedObject(unit_in, NULL, NULL);
            if (obj_str == NULL) {
                return 0;
            }
            strobj = obj_str;
        }
        else {
            Py_INCREF(unit_in);
            strobj = unit_in;
        }

        Py_ssize_t len;
        char const *str = PyUnicode_AsUTF8AndSize(strobj, &len);
        if (str == NULL) {
            Py_DECREF(strobj);
            goto fail;
        }

        /*
         * unit == NPY_FR_ERROR means to autodetect the unit
         * from the datetime data
         * */
        # 如果单位为 NPY_FR_ERROR,则从日期时间数据中自动检测单位
        if (strcmp(str, "auto") == 0) {
            unit = NPY_FR_ERROR;
        }
        else {
            unit = parse_datetime_unit_from_string(str, len, NULL);
            if (unit == NPY_FR_ERROR) {
                Py_DECREF(strobj);
                goto fail;
            }
        }
        Py_DECREF(strobj);

        if (unit != NPY_FR_ERROR &&
                !can_cast_datetime64_units(meta->base, unit, casting)) {
            PyErr_Format(PyExc_TypeError, "Cannot create a datetime "
                        "string as units '%s' from a NumPy datetime "
                        "with units '%s' according to the rule %s",
                        _datetime_strings[unit],
                        _datetime_strings[meta->base],
                         npy_casting_to_string(casting));
            goto fail;
        }
    }

    /* Get the input time zone */
    # 获取输入的时区
    // 检查时区对象是否非空
    if (timezone_obj != NULL) {
        PyObject *strobj;
        // 如果时区对象是字节对象
        if (PyBytes_Check(timezone_obj)) {
            /* accept bytes input */
            // 将字节对象转换为Unicode字符串对象
            PyObject *obj_str = PyUnicode_FromEncodedObject(timezone_obj, NULL, NULL);
            if (obj_str == NULL) {
                // 转换失败时跳转到错误处理
                goto fail;
            }
            strobj = obj_str;
        }
        else {
            // 增加时区对象的引用计数
            Py_INCREF(timezone_obj);
            strobj = timezone_obj;
        }

        // 将strobj赋值给timezone_obj,并释放之前的引用
        Py_SETREF(timezone_obj, strobj);

        /* Check for the supported string inputs */
        // 检查时区对象是否是Unicode字符串
        if (PyUnicode_Check(timezone_obj)) {
            Py_ssize_t len;
            // 获取Unicode字符串的UTF-8表示及其长度
            char const *str = PyUnicode_AsUTF8AndSize(timezone_obj, &len);
            if (str == NULL) {
                // 获取失败时跳转到错误处理
                goto fail;
            }

            // 根据字符串内容设置local和utc标志位
            if (strcmp(str, "local") == 0) {
                local = 1;
                utc = 0;
                Py_DECREF(timezone_obj);
                timezone_obj = NULL;
            }
            else if (strcmp(str, "UTC") == 0) {
                local = 0;
                utc = 1;
                Py_DECREF(timezone_obj);
                timezone_obj = NULL;
            }
            else if (strcmp(str, "naive") == 0) {
                local = 0;
                utc = 0;
                Py_DECREF(timezone_obj);
                timezone_obj = NULL;
            }
            else {
                // 抛出值错误异常,指示不支持的时区字符串输入
                PyErr_Format(PyExc_ValueError, "Unsupported timezone "
                            "input string \"%s\"", str);
                goto fail;
            }
        }
        /* Otherwise assume it's a Python TZInfo, or acts like one */
        else {
            // 否则认为是Python的TZInfo对象或类似对象,设置local标志位
            local = 1;
        }
    }

    /* Get a string size long enough for any datetimes we're given */
    // 获取一个足够长的字符串大小以适应任何给定的日期时间
    strsize = NpyDatetime_GetDatetimeISO8601StrLen(local, unit);
    /*
     * For Python3, allocate the output array as a UNICODE array, so
     * that it will behave as strings properly
     */
    // 对于Python3,分配输出数组作为UNICODE数组,以便它正确地作为字符串处理
    op_dtypes[1] = PyArray_DescrNewFromType(NPY_UNICODE);
    if (op_dtypes[1] == NULL) {
        // 分配失败时跳转到错误处理
        goto fail;
    }
    op_dtypes[1]->elsize = strsize * 4;
    /* This steals the UNICODE dtype reference in op_dtypes[1] */
    // 这里窃取op_dtypes[1]中的UNICODE dtype引用
    op[1] = (PyArrayObject *)PyArray_NewLikeArray(op[0],
                                        NPY_KEEPORDER, op_dtypes[1], 1);
    if (op[1] == NULL) {
        op_dtypes[1] = NULL;
        goto fail;
    }
    /* Create the iteration string data type (always ASCII string) */
    // 创建迭代字符串数据类型(始终为ASCII字符串)
    op_dtypes[1] = PyArray_DescrNewFromType(NPY_STRING);
    if (op_dtypes[1] == NULL) {
        // 创建失败时跳转到错误处理
        goto fail;
    }
    op_dtypes[1]->elsize = strsize;

    // 设置迭代器标志和操作标志
    flags = NPY_ITER_ZEROSIZE_OK|
            NPY_ITER_BUFFERED;
    op_flags[0] = NPY_ITER_READONLY|
                  NPY_ITER_ALIGNED;
    op_flags[1] = NPY_ITER_WRITEONLY|
                  NPY_ITER_ALLOCATE;

    // 创建多重迭代器对象
    iter = NpyIter_MultiNew(2, op, flags, NPY_KEEPORDER, NPY_UNSAFE_CASTING,
                            op_flags, op_dtypes);
    if (iter == NULL) {
        // 创建失败时跳转到错误处理
        goto fail;
    }
    if (NpyIter_GetIterSize(iter) != 0) {
        // 获取迭代器的大小,如果不为0,则执行以下操作
        NpyIter_IterNextFunc *iternext;
        // 声明迭代器的下一个函数指针
        char **dataptr;
        // 声明数据指针的数组
        npy_datetime dt;
        // 声明numpy的日期时间变量
        npy_datetimestruct dts;
        // 声明numpy的日期时间结构体变量

        iternext = NpyIter_GetIterNext(iter, NULL);
        // 获取迭代器的下一个函数指针,传入NULL表示不需要传播错误
        if (iternext == NULL) {
            // 如果获取迭代器的下一个函数指针失败,则跳转到错误处理部分
            goto fail;
        }
        dataptr = NpyIter_GetDataPtrArray(iter);
        // 获取迭代器的数据指针数组

        do {
            int tzoffset = -1;
            // 声明时区偏移量变量并初始化为-1

            /* Get the datetime */
            // 获取日期时间
            dt = *(npy_datetime *)dataptr[0];

            /* Convert it to a struct */
            // 将其转换为结构体
            if (NpyDatetime_ConvertDatetime64ToDatetimeStruct(meta, dt, &dts) < 0) {
                // 如果转换日期时间失败,则跳转到错误处理部分
                goto fail;
            }

            /* Get the tzoffset from the timezone if provided */
            // 如果提供了本地化和时区对象,则获取时区偏移量
            if (local && timezone_obj != NULL) {
                tzoffset = get_tzoffset_from_pytzinfo(timezone_obj, &dts);
                // 调用函数获取时区偏移量
                if (tzoffset == -1) {
                    // 如果获取时区偏移量失败,则跳转到错误处理部分
                    goto fail;
                }
            }

            /* Zero the destination string completely */
            // 将目标字符串完全置零
            memset(dataptr[1], 0, strsize);

            /* Convert that into a string */
            // 将其转换为字符串
            if (NpyDatetime_MakeISO8601Datetime(&dts, (char *)dataptr[1], strsize,
                                local, utc, unit, tzoffset, casting) < 0) {
                // 如果转换为ISO8601格式日期时间字符串失败,则跳转到错误处理部分
                goto fail;
            }
        } while(iternext(iter));
        // 使用迭代器的下一个函数处理所有数据

    }

    ret = NpyIter_GetOperandArray(iter)[1];
    // 获取迭代器的操作数数组中的第二个操作数
    Py_INCREF(ret);
    // 增加返回数组的引用计数

    Py_XDECREF(timezone_obj);
    // 释放时区对象的引用
    Py_XDECREF(op[0]);
    // 释放操作数数组中的第一个操作数的引用
    Py_XDECREF(op[1]);
    // 释放操作数数组中的第二个操作数的引用
    Py_XDECREF(op_dtypes[0]);
    // 释放操作数据类型数组中的第一个元素的引用
    Py_XDECREF(op_dtypes[1]);
    // 释放操作数据类型数组中的第二个元素的引用
    if (iter != NULL) {
        // 如果迭代器不为NULL,则释放迭代器
        NpyIter_Deallocate(iter);
    }

    return PyArray_Return(ret);
    // 返回增加了引用计数的返回数组
fail:
    // 释放引用计数并清理内存:释放时区对象的引用
    Py_XDECREF(timezone_obj);
    // 释放引用计数并清理内存:释放操作数数组中的第一个操作数对象
    Py_XDECREF(op[0]);
    // 释放引用计数并清理内存:释放操作数数组中的第二个操作数对象
    Py_XDECREF(op[1]);
    // 释放引用计数并清理内存:释放操作数数据类型数组中的第一个数据类型对象
    Py_XDECREF(op_dtypes[0]);
    // 释放引用计数并清理内存:释放操作数数据类型数组中的第二个数据类型对象
    Py_XDECREF(op_dtypes[1]);
    // 如果迭代器对象不为空,则释放迭代器对象的内存
    if (iter != NULL) {
        NpyIter_Deallocate(iter);
    }

    // 函数执行失败,返回空指针(NULL)
    return NULL;
}

.\numpy\numpy\_core\src\multiarray\datetime_strings.h

#ifndef NUMPY_CORE_SRC_MULTIARRAY_DATETIME_STRINGS_H_
#define NUMPY_CORE_SRC_MULTIARRAY_DATETIME_STRINGS_H_

/*
 * This is the Python-exposed datetime_as_string function.
 */
# 定义一个条件编译指令,防止重复包含同一头文件
NPY_NO_EXPORT PyObject *
# 定义函数 array_datetime_as_string,接受三个参数:self(未使用)、args 和 kwds
array_datetime_as_string(PyObject *NPY_UNUSED(self), PyObject *args,
                                PyObject *kwds);

#endif  /* NUMPY_CORE_SRC_MULTIARRAY_DATETIME_STRINGS_H_ */

.\numpy\numpy\_core\src\multiarray\descriptor.c

/* Array Descr Object */

/* Define to use the latest NumPy API version */
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
/* Define to enable multiarray module */
#define _MULTIARRAYMODULE

/* Define to clean PY_SSIZE_T definition */
#define PY_SSIZE_T_CLEAN
/* Include Python.h header file */
#include <Python.h>
/* Include structmember.h header file for structure member handling */
#include <structmember.h>

/* Include errno.h header file for error number definitions */
#include <errno.h>

/* Include NumPy core arrayobject header file */
#include "numpy/arrayobject.h"
/* Include NumPy array scalars header file */
#include "numpy/arrayscalars.h"
/* Include NumPy math functions header file */
#include "numpy/npy_math.h"

/* Include NumPy configuration header file */
#include "npy_config.h"
/* Include NumPy ctypes header file for ctypes integration */
#include "npy_ctypes.h"
/* Include NumPy import header file */
#include "npy_import.h"

/* Include datetime functions from _datetime.h */
#include "_datetime.h"
/* Include common functions from common.h */
#include "common.h"
/* Include conversion utilities from conversion_utils.h */
#include "conversion_utils.h"
/* Include templ_common.h for common templated functions */
#include "templ_common.h"
/* Include descriptor.h for dtype descriptor definitions */
#include "descriptor.h"
/* Include static data definitions from npy_static_data.h */
#include "npy_static_data.h"
/* Include multiarraymodule.h for thread-unsafe state access */
#include "multiarraymodule.h"
/* Include allocation functions from alloc.h */
#include "alloc.h"
/* Include assert.h header file for assertions */
#include "assert.h"
/* Include buffer definitions from npy_buffer.h */
#include "npy_buffer.h"
/* Include dtype metadata from dtypemeta.h */
#include "dtypemeta.h"
/* Include string dtype definitions from stringdtype/dtype.h */
#include "stringdtype/dtype.h"

/* Define PyDictProxy_Check macro if not already defined */
#ifndef PyDictProxy_Check
#define PyDictProxy_Check(obj) (Py_TYPE(obj) == &PyDictProxy_Type)
#endif

/* Initialize global variable for storing type dictionary */
static PyObject *typeDict = NULL;   /* Must be explicitly loaded */

/* Declare function for trying to convert from an inherited tuple */
static PyArray_Descr *
_try_convert_from_inherit_tuple(PyArray_Descr *type, PyObject *newobj);

/* Declare function for converting from any Python object */
static PyArray_Descr *
_convert_from_any(PyObject *obj, int align);

/*
 * This function creates a dtype object when the object is a ctypes subclass.
 *
 * Returns `Py_NotImplemented` if the type is not a ctypes subclass.
 */
static PyArray_Descr *
_try_convert_from_ctypes_type(PyTypeObject *type)
{
    PyObject *_numpy_dtype_ctypes;
    PyObject *res;

    /* Check if the given type is a ctypes subclass */
    if (!npy_ctypes_check(type)) {
        /* Increment reference count and return Py_NotImplemented */
        Py_INCREF(Py_NotImplemented);
        return (PyArray_Descr *)Py_NotImplemented;
    }

    /* Import the numpy._core._dtype_ctypes module */
    _numpy_dtype_ctypes = PyImport_ImportModule("numpy._core._dtype_ctypes");
    if (_numpy_dtype_ctypes == NULL) {
        return NULL;  /* Return NULL on import failure */
    }
    /* Call dtype_from_ctypes_type function from _numpy_dtype_ctypes module */
    res = PyObject_CallMethod(_numpy_dtype_ctypes, "dtype_from_ctypes_type", "O", (PyObject *)type);
    Py_DECREF(_numpy_dtype_ctypes);  /* Decrement reference count of module */

    if (res == NULL) {
        return NULL;  /* Return NULL if call fails */
    }

    /*
     * Sanity check that dtype_from_ctypes_type returned the correct type,
     * since an incorrect return type could lead to segfaults.
     */
    if (!PyObject_TypeCheck(res, &PyArrayDescr_Type)) {
        Py_DECREF(res);  /* Decrement reference count if type check fails */
        PyErr_BadInternalCall();  /* Raise internal call error */
        return NULL;  /* Return NULL on error */
    }

    return (PyArray_Descr *)res;  /* Return dtype object */
}

/*
 * This function creates a dtype object when the object has a "dtype" attribute,
 * and it can be converted to a dtype object.
 *
 * Returns `Py_NotImplemented` if this is not possible.
 * Currently the only failure mode for a NULL return is a RecursionError.
 */
static PyArray_Descr *
_try_convert_from_dtype_attr(PyObject *obj)
{
    /* Attempt to retrieve the "dtype" attribute from the object */
    PyObject *dtypedescr = PyObject_GetAttrString(obj, "dtype");
    if (dtypedescr == NULL) {
        /*
         * Handle case where fetching the attribute fails, possibly due to
         * recursion limit being hit.
         */
        goto fail;
    }
    /* Continue function implementation here */
    /* 如果给定的数据类型描述符是一个有效的数组描述符,则直接返回它 */
    if (PyArray_DescrCheck(dtypedescr)) {
        /* `dtype` 属性已经是一个有效的描述符 */
        return (PyArray_Descr *)dtypedescr;
    }

    /* 进入递归调用保护区域,用于转换给定数据类型的`.dtype`属性 */
    if (Py_EnterRecursiveCall(
            " while trying to convert the given data type from its "
            "`.dtype` attribute.") != 0) {
        Py_DECREF(dtypedescr);
        return NULL;
    }

    /* 调用_convert_from_any函数进行数据类型转换 */
    PyArray_Descr *newdescr = _convert_from_any(dtypedescr, 0);
    Py_DECREF(dtypedescr);
    Py_LeaveRecursiveCall();

    /* 如果转换失败,则跳转到标签fail处处理 */
    if (newdescr == NULL) {
        goto fail;
    }

    /* 在202115日被弃用,NumPy 1.21版本开始 */
    /* 发出弃用警告,说明`.dtype`属性必须是有效的dtype实例,可能需要通过`np.dtype(data_type.dtype)`强制转换 */
    if (DEPRECATE("in the future the `.dtype` attribute of a given data"
                  "type object must be a valid dtype instance. "
                  "`data_type.dtype` may need to be coerced using "
                  "`np.dtype(data_type.dtype)`. (Deprecated NumPy 1.20)") < 0) {
        Py_DECREF(newdescr);
        return NULL;
    }

    /* 返回新的数据类型描述符 */
    return newdescr;

  fail:
    /* 处理失败的情况,忽略除递归错误外的所有异常,以便给ctypes一个充分的尝试机会 */
    if (!PyErr_ExceptionMatches(PyExc_RecursionError)) {
        PyErr_Clear();
        /* 返回Py_NotImplemented对象,表示操作未实现 */
        Py_INCREF(Py_NotImplemented);
        return (PyArray_Descr *)Py_NotImplemented;
    }
    return NULL;
/* Expose to another file with a prefixed name */
/* 将此函数暴露给带有前缀名称的另一个文件 */
NPY_NO_EXPORT PyArray_Descr *
_arraydescr_try_convert_from_dtype_attr(PyObject *obj)
{
    /* 调用内部函数_try_convert_from_dtype_attr处理对象 */
    return _try_convert_from_dtype_attr(obj);
}

/*
 * Sets the global typeDict object, which is a dictionary mapping
 * dtype names to numpy scalar types.
 */
/*
 * 设置全局的typeDict对象,这是一个将dtype名称映射到numpy标量类型的字典。
 */
NPY_NO_EXPORT PyObject *
array_set_typeDict(PyObject *NPY_UNUSED(ignored), PyObject *args)
{
    PyObject *dict;

    /* 尝试解析参数元组,获取字典对象 */
    if (!PyArg_ParseTuple(args, "O:set_typeDict", &dict)) {
        return NULL;
    }
    /* 减少旧的引用(如果有的话) */
    Py_XDECREF(typeDict);
    /* 将typeDict设置为新的字典对象 */
    typeDict = dict;
    /* 创建对字典对象的内部引用 */
    Py_INCREF(dict);
    /* 返回None对象 */
    Py_RETURN_NONE;
}

#define _chk_byteorder(arg) (arg == '>' || arg == '<' ||        \
                             arg == '|' || arg == '=')

static int
_check_for_commastring(const char *type, Py_ssize_t len)
{
    Py_ssize_t i;
    int sqbracket;

    /* 检查字符串开头是否为整数 */
    if ((type[0] >= '0'
                && type[0] <= '9')
            || ((len > 1)
                && _chk_byteorder(type[0])
                && (type[1] >= '0'
                && type[1] <= '9'))) {
        return 1;
    }
    /* 检查空元组 */
    if (((len > 1)
                && (type[0] == '('
                && type[1] == ')'))
            || ((len > 3)
                && _chk_byteorder(type[0])
                && (type[1] == '('
                && type[2] == ')'))) {
        return 1;
    }
    /*
     * 检查方括号 [] 外的逗号存在。这允许参数化dtype中的逗号。
     */
    sqbracket = 0;
    for (i = 0; i < len; i++) {
        switch (type[i]) {
            case ',':
                if (sqbracket == 0) {
                    return 1;
                }
                break;
            case '[':
                ++sqbracket;
                break;
            case ']':
                --sqbracket;
                break;
        }
    }
    return 0;
}

#undef _chk_byteorder

static int
is_datetime_typestr(char const *type, Py_ssize_t len)
{
    /* 检查长度小于2的情况 */
    if (len < 2) {
        return 0;
    }
    /* 检查是否以'M8''m8'开头 */
    if (type[1] == '8' && (type[0] == 'M' || type[0] == 'm')) {
        return 1;
    }
    /* 检查长度小于10的情况 */
    if (len < 10) {
        return 0;
    }
    /* 检查是否以"datetime64"开头 */
    if (strncmp(type, "datetime64", 10) == 0) {
        return 1;
    }
    /* 检查长度小于11的情况 */
    if (len < 11) {
        return 0;
    }
    /* 检查是否以"timedelta64"开头 */
    if (strncmp(type, "timedelta64", 11) == 0) {
        return 1;
    }
    return 0;
}

static PyArray_Descr *
_convert_from_tuple(PyObject *obj, int align)
{
    /* 检查元组大小是否为2 */
    if (PyTuple_GET_SIZE(obj) != 2) {
        PyErr_Format(PyExc_TypeError,
            "Tuple must have size 2, but has size %zd",
            PyTuple_GET_SIZE(obj));
        return NULL;
    }
    /* 尝试将第一个元素解析为类型 */
    PyArray_Descr *type = _convert_from_any(PyTuple_GET_ITEM(obj, 0), align);
    if (type == NULL) {
        return NULL;
    }
    /* 获取元组的第二个元素 */
    PyObject *val = PyTuple_GET_ITEM(obj,1);
    /* 尝试将下一个元素解释为类型 */
    // 尝试将给定类型和值转换为描述符对象
    PyArray_Descr *res = _try_convert_from_inherit_tuple(type, val);
    
    // 如果转换成功,返回描述符对象,释放类型对象并结束函数
    if ((PyObject *)res != Py_NotImplemented) {
        Py_DECREF(type);
        return res;
    }
    
    // 若转换失败但未崩溃,则继续执行以下代码

    // 如果类型对象是无大小的数据类型
    if (PyDataType_ISUNSIZED(type)) {
        // 尝试解析元组中的下一个项作为类型大小
        int itemsize = PyArray_PyIntAsInt(PyTuple_GET_ITEM(obj,1));

        // 如果解析出错,设置异常并释放类型对象并返回空
        if (error_converting(itemsize)) {
            PyErr_SetString(PyExc_ValueError,
                    "invalid itemsize in generic type tuple");
            Py_DECREF(type);
            return NULL;
        }
        
        // 替换类型对象的描述符,如果失败则返回空
        PyArray_DESCR_REPLACE(type);
        if (type == NULL) {
            return NULL;
        }
        
        // 如果类型是 NPY_UNICODE,设置元素大小为 itemsize 左移 2if (type->type_num == NPY_UNICODE) {
            type->elsize = itemsize << 2;
        }
        else {
            type->elsize = itemsize;
        }
        
        // 返回修改后的类型对象
        return type;
    }
    // 如果类型对象有元数据并且值是字典或字典代理类型
    else if (type->metadata && (PyDict_Check(val) || PyDictProxy_Check(val))) {
        // 假设值是元数据字典,尝试将其合并到类型对象的元数据中
        if (PyDict_Merge(type->metadata, val, 0) == -1) {
            Py_DECREF(type);
            return NULL;
        }
        
        // 返回更新后的类型对象
        return type;
    }
    
    // 如果执行到这里,意味着发生了错误,清理并返回空
    fail:
        Py_XDECREF(type);
        npy_free_cache_dim_obj(shape);
        return NULL;
}

/*
 * obj is a list.  Each item is a tuple with
 *
 * (field-name, data-type (either a list or a string), and an optional
 * shape parameter).
 *
 * field-name can be a string or a 2-tuple
 * data-type can now be a list, string, or 2-tuple
 *          (string, metadata dictionary)
 */
static PyArray_Descr *
_convert_from_array_descr(PyObject *obj, int align)
{
    // 获取列表 obj 的长度
    int n = PyList_GET_SIZE(obj);
    // 创建一个元组 nameslist,长度为 n
    PyObject *nameslist = PyTuple_New(n);
    if (!nameslist) {
        return NULL;
    }

    /* Types with fields need the Python C API for field access */
    // 定义 dtypeflags 标志,需要使用 Python C API
    char dtypeflags = NPY_NEEDS_PYAPI;
    // 初始化 maxalign 和 totalsize
    int maxalign = 1;
    int totalsize = 0;
    // 创建一个空的字典 fields
    PyObject *fields = PyDict_New();
    if (!fields) {
        return NULL;
    }
    // 此处多余的右括号应删除
    }

    // 如果 maxalign 大于 1,则调整 totalsize 为下一个对齐偏移量
    if (maxalign > 1) {
        totalsize = NPY_NEXT_ALIGNED_OFFSET(totalsize, maxalign);
    }

    // 创建一个新的 _PyArray_LegacyDescr 结构体,类型为 NPY_VOID
    _PyArray_LegacyDescr *new = (_PyArray_LegacyDescr *)PyArray_DescrNewFromType(NPY_VOID);
    if (new == NULL) {
        goto fail;
    }
    // 设置新结构体的字段和名称列表等属性
    new->fields = fields;
    new->names = nameslist;
    new->elsize = totalsize;
    new->flags = dtypeflags;

    /* Structured arrays get a sticky aligned bit */
    // 如果 align 为真,设置新结构体的 flags 包括 NPY_ALIGNED_STRUCT
    if (align) {
        new->flags |= NPY_ALIGNED_STRUCT;
        new->alignment = maxalign;
    }
    // 返回 PyArray_Descr 指针类型的 new 结构体
    return (PyArray_Descr *)new;

 fail:
    // 失败时释放 fields 和 nameslist,返回 NULL
    Py_DECREF(fields);
    Py_DECREF(nameslist);
    return NULL;

}

/*
 * a list specifying a data-type can just be
 * a list of formats.  The names for the fields
 * will default to f0, f1, f2, and so forth.
 */
static PyArray_Descr *
_convert_from_list(PyObject *obj, int align)
{
    // 获取列表 obj 的长度
    int n = PyList_GET_SIZE(obj);
    /*
     * Ignore any empty string at end which _internal._commastring
     * can produce
     */
    // 获取列表 obj 中的最后一个元素
    PyObject *last_item = PyList_GET_ITEM(obj, n-1);
    // 如果最后一个元素是字符串类型
    if (PyUnicode_Check(last_item)) {
        // 获取字符串的长度
        Py_ssize_t s = PySequence_Size(last_item);
        if (s < 0) {
            return NULL;
        }
        // 如果字符串长度为 0,将列表长度 n 减 1
        if (s == 0) {
            n = n - 1;
        }
    }
    // 如果列表长度为 0,抛出值错误异常
    if (n == 0) {
        PyErr_SetString(PyExc_ValueError, "Expected at least one field name");
        return NULL;
    }
    // 创建一个元组 nameslist,长度为 n
    PyObject *nameslist = PyTuple_New(n);
    if (!nameslist) {
        return NULL;
    }
    // 创建一个空的字典 fields
    PyObject *fields = PyDict_New();
    if (!fields) {
        Py_DECREF(nameslist);
        return NULL;
    }

    /* Types with fields need the Python C API for field access */
    // 定义 dtypeflags 标志,需要使用 Python C API
    char dtypeflags = NPY_NEEDS_PYAPI;
    // 初始化 maxalign 和 totalsize
    int maxalign = 1;
    int totalsize = 0;
    for (int i = 0; i < n; i++) {
        // 从 Python 列表中获取第 i 个元素,并尝试将其转换为 PyArray_Descr 结构
        PyArray_Descr *conv = _convert_from_any(
                PyList_GET_ITEM(obj, i), align);
        // 如果转换失败(返回 NULL),跳转到错误处理标签
        if (conv == NULL) {
            goto fail;
        }
        // 将 conv 结构中的 flags 与 NPY_FROM_FIELDS 按位或,更新 dtypeflags
        dtypeflags |= (conv->flags & NPY_FROM_FIELDS);
        // 如果需要按照指定对齐方式对齐
        if (align) {
            // 获取 conv 结构的对齐值
            int _align = conv->alignment;
            // 如果对齐值大于 1,则按照该对齐值对 totalsize 进行向上对齐
            if (_align > 1) {
                totalsize = NPY_NEXT_ALIGNED_OFFSET(totalsize, _align);
            }
            // 更新 maxalign 为当前计算出的对齐值和已有 maxalign 的最大值
            maxalign = PyArray_MAX(maxalign, _align);
        }
        // 根据 totalsize 创建一个 PyLong 对象作为 size_obj
        PyObject *size_obj = PyLong_FromLong((long) totalsize);
        // 如果创建失败,释放 conv 并跳转到错误处理标签
        if (!size_obj) {
            Py_DECREF(conv);
            goto fail;
        }
        // 创建一个新的元组对象 tup,包含 conv 和 size_obj
        PyObject *tup = PyTuple_New(2);
        // 如果创建失败,释放 size_obj 和 conv,并跳转到错误处理标签
        if (!tup) {
            Py_DECREF(size_obj);
            Py_DECREF(conv);
            goto fail;
        }
        // 设置 tup 的第一个元素为 conv,第二个元素为 size_obj
        PyTuple_SET_ITEM(tup, 0, (PyObject *)conv);
        PyTuple_SET_ITEM(tup, 1, size_obj);
        // 根据索引 i 创建一个新的 key,格式为 "f%d"
        PyObject *key = PyUnicode_FromFormat("f%d", i);
        // 如果创建失败,释放 tup,并跳转到错误处理标签
        if (!key) {
            Py_DECREF(tup);
            goto fail;
        }
        // 将 key 添加到 nameslist 中,同时 key 的引用计数会增加("steals a reference to key")
        PyTuple_SET_ITEM(nameslist, i, key);
        // 将 tup 添加到 fields 字典中,key 为 key
        int ret = PyDict_SetItem(fields, key, tup);
        // 释放 tup,并如果 PyDict_SetItem 返回负值(失败),跳转到错误处理标签
        Py_DECREF(tup);
        if (ret < 0) {
            goto fail;
        }
        // 更新 totalsize,增加 conv 的元素大小
        totalsize += conv->elsize;
    }
    // 创建一个新的 _PyArray_LegacyDescr 结构,类型为 NPY_VOID
    _PyArray_LegacyDescr *new = (_PyArray_LegacyDescr *)PyArray_DescrNewFromType(NPY_VOID);
    // 如果创建失败,跳转到错误处理标签
    if (new == NULL) {
        goto fail;
    }
    // 设置 new 结构的 fields、names 和 flags
    new->fields = fields;
    new->names = nameslist;
    new->flags = dtypeflags;
    // 如果最大对齐值大于 1,按照 maxalign 对 totalsize 进行向上对齐
    if (maxalign > 1) {
        totalsize = NPY_NEXT_ALIGNED_OFFSET(totalsize, maxalign);
    }
    // 如果需要对结构数组进行对齐,设置 NPY_ALIGNED_STRUCT 标志并更新对齐值
    if (align) {
        new->flags |= NPY_ALIGNED_STRUCT;
        new->alignment = maxalign;
    }
    // 设置 new 结构的元素大小为 totalsize,并返回该结构的指针类型
    new->elsize = totalsize;
    return (PyArray_Descr *)new;

 fail:
    // 错误处理标签:释放 nameslist 和 fields,并返回 NULL
    Py_DECREF(nameslist);
    Py_DECREF(fields);
    return NULL;
/*
 * helper function for _try_convert_from_inherit_tuple to disallow dtypes of the form
 * (old_dtype, new_dtype) where either of the dtypes contains python
 * objects - these dtypes are not useful and can be a source of segfaults,
 * when an attempt is made to interpret a python object as a different dtype
 * or vice versa
 * an exception is made for dtypes of the form ('O', [('name', 'O')]), which
 * people have been using to add a field to an object array without fields
 */
static int
_validate_union_object_dtype(_PyArray_LegacyDescr *new, _PyArray_LegacyDescr *conv)
{
    PyObject *name, *tup;
    PyArray_Descr *dtype;

    // 如果两个描述符都不是引用检查,说明它们不包含Python对象
    if (!PyDataType_REFCHK((PyArray_Descr *)new)
            && !PyDataType_REFCHK((PyArray_Descr *)conv)) {
        return 0;
    }
    // 如果新描述符有字段或者种类不是 'O'(Python对象),则验证失败
    if (PyDataType_HASFIELDS(new) || new->kind != 'O') {
        goto fail;
    }
    // 如果旧描述符没有字段或字段元组大小不为1,则验证失败
    if (!PyDataType_HASFIELDS(conv) || PyTuple_GET_SIZE(conv->names) != 1) {
        goto fail;
    }
    // 获取字段名
    name = PyTuple_GET_ITEM(conv->names, 0);
    if (name == NULL) {
        return -1;
    }
    // 从字段字典中获取名字对应的项
    tup = PyDict_GetItemWithError(conv->fields, name);
    # 如果元组对象 `tup` 是 NULL,表示传入的参数未正确获取,需要进行错误处理
    if (tup == NULL) {
        # 如果没有已设置的 Python 异常状态,说明字段名未正确包含在字段中
        /* fields was missing the name it claimed to contain */
        PyErr_BadInternalCall();
        # 返回错误码 -1
        return -1;
    }
    # 从元组 `tup` 中获取第一个元素,应该是一个 PyArray_Descr 对象指针
    dtype = (PyArray_Descr *)PyTuple_GET_ITEM(tup, 0);
    # 如果获取的 `dtype` 是 NULL,说明获取失败,返回错误码 -1
    if (dtype == NULL) {
        return -1;
    }
    # 如果 `dtype` 的类型不是对象('O'),跳转到错误处理标签 `fail`
    if (dtype->kind != 'O') {
        goto fail;
    }
    # 如果以上条件都没有问题,则返回成功标志 0
    return 0;
/*
 * Try to convert a descriptor from an inherit tuple to a legacy descriptor.
 * This function handles cases where the new data-type inherits from the old
 * data-type, ensuring compatibility or raising appropriate errors if not.
 *
 * Parameters:
 * - type: The original data descriptor to convert from.
 * - newobj: The new object descriptor to convert to.
 *
 * Returns:
 * - A new PyArray_Descr object if successful, or Py_NotImplemented if conversion fails.
 */

static PyArray_Descr *
_try_convert_from_inherit_tuple(PyArray_Descr *type, PyObject *newobj)
{
    // Check if newobj is a scalar or tuple of integers
    if (PyArray_IsScalar(newobj, Integer) || _is_tuple_of_integers(newobj)) {
        /* It's a subarray or flexible type instead */
        Py_INCREF(Py_NotImplemented);
        return (PyArray_Descr *)Py_NotImplemented;
    }

    // Attempt to convert newobj to a legacy descriptor
    _PyArray_LegacyDescr *conv = (_PyArray_LegacyDescr *)_convert_from_any(newobj, 0);
    if (conv == NULL) {
        /* Conversion failed, let someone else handle it */
        PyErr_Clear();
        Py_INCREF(Py_NotImplemented);
        return (PyArray_Descr *)Py_NotImplemented;
    }

    // Ensure both type and conv are legacy descriptors
    if (!PyDataType_ISLEGACY(type) || !PyDataType_ISLEGACY(conv)) {
        /* New-style DTypes not supported */
        Py_DECREF(conv);
        Py_INCREF(Py_NotImplemented);
        return (PyArray_Descr *)Py_NotImplemented;
    }

    // Create a new legacy descriptor based on type
    _PyArray_LegacyDescr *new = (_PyArray_LegacyDescr *)PyArray_DescrNew(type);
    if (new == NULL) {
        // Handle memory allocation failure
        goto fail;
    }

    // Handle unsized type or mismatched elsize
    if (PyDataType_ISUNSIZED(new)) {
        new->elsize = conv->elsize;
    } else if (new->elsize != conv->elsize) {
        // Error if elsize mismatch
        PyErr_SetString(PyExc_ValueError,
                "mismatch in size of old and new data-descriptor");
        Py_DECREF(new);
        goto fail;
    } else if (_validate_union_object_dtype(new, conv) < 0) {
        // Validate union object data type
        Py_DECREF(new);
        goto fail;
    }

    // Copy fields and metadata from conv to new
    if (PyDataType_HASFIELDS(conv)) {
        Py_XDECREF(new->fields);
        new->fields = conv->fields;
        Py_XINCREF(new->fields);

        Py_XDECREF(new->names);
        new->names = conv->names;
        Py_XINCREF(new->names);
    }
    if (conv->metadata != NULL) {
        Py_XDECREF(new->metadata);
        new->metadata = conv->metadata;
        Py_XINCREF(new->metadata);
    }

fail:
    // Handle failure by setting appropriate error message
    PyErr_SetString(PyExc_ValueError,
            "dtypes of the form (old_dtype, new_dtype) containing the object "
            "dtype are not supported");
    return -1;
}
    /*
     * Certain flags must be inherited from the fields.  This is needed
     * only for void dtypes (or subclasses of it such as a record dtype).
     * For other dtypes, the field part will only be used for direct field
     * access and thus flag inheritance should not be necessary.
     * (We only allow object fields if the dtype is object as well.)
     * This ensures copying over of the NPY_FROM_FIELDS "inherited" flags.
     */
    如果新的数据类型是 NPY_VOID 类型:
        // 将新的数据类型的标志位设置为从 conv 中获得的标志位
        new->flags = conv->flags;
    
    // 释放 conv 对象的引用计数
    Py_DECREF(conv);
    // 返回一个新的 PyArray_Descr 指针,即 new 指针强制转换
    return (PyArray_Descr *)new;

 fail:
    // 在发生错误时释放 conv 对象的引用计数
    Py_DECREF(conv);
    // 返回 NULL 表示操作失败
    return NULL;
/*
 * Validates that any field of the structured array 'dtype' which has
 * the NPY_ITEM_HASOBJECT flag set does not overlap with another field.
 *
 * This algorithm is worst case O(n^2). It could be done with a sort
 * and sweep algorithm, but the structured dtype representation is
 * rather ugly right now, so writing something better can wait until
 * that representation is made sane.
 *
 * Returns 0 on success, -1 if an exception is raised.
 */
static int
_validate_object_field_overlap(_PyArray_LegacyDescr *dtype)
{
    PyObject *names, *fields, *key, *tup, *title;
    Py_ssize_t i, j, names_size;
    PyArray_Descr *fld_dtype, *fld2_dtype;
    int fld_offset, fld2_offset;

    /* Get some properties from the dtype */
    names = dtype->names;  // 获取 dtype 中的字段名元组
    names_size = PyTuple_GET_SIZE(names);  // 获取字段名元组的大小
    fields = dtype->fields;  // 获取 dtype 中的字段字典

    // 循环遍历所有字段名
    for (i = 0; i < names_size; ++i) {
        key = PyTuple_GET_ITEM(names, i);  // 获取当前字段名
        if (key == NULL) {
            return -1;  // 如果字段名为空,返回异常
        }
        tup = PyDict_GetItemWithError(fields, key);  // 从字段字典中获取字段元组
        if (tup == NULL) {
            if (!PyErr_Occurred()) {
                /* fields was missing the name it claimed to contain */
                PyErr_BadInternalCall();  // 如果字段字典中缺少相应字段名,抛出异常
            }
            return -1;
        }
        if (!PyArg_ParseTuple(tup, "Oi|O", &fld_dtype, &fld_offset, &title)) {
            return -1;  // 解析字段元组失败,返回异常
        }

        /* If this field has objects, check for overlaps */
        if (PyDataType_REFCHK(fld_dtype)) {  // 如果字段类型包含引用类型,进行重叠检查
            // 再次遍历所有字段名
            for (j = 0; j < names_size; ++j) {
                if (i != j) {
                    key = PyTuple_GET_ITEM(names, j);  // 获取另一个字段名
                    if (key == NULL) {
                        return -1;  // 如果字段名为空,返回异常
                    }
                    tup = PyDict_GetItemWithError(fields, key);  // 获取另一个字段元组
                    if (tup == NULL) {
                        if (!PyErr_Occurred()) {
                            /* fields was missing the name it claimed to contain */
                            PyErr_BadInternalCall();  // 如果字段字典中缺少相应字段名,抛出异常
                        }
                        return -1;
                    }
                    if (!PyArg_ParseTuple(tup, "Oi|O", &fld2_dtype,
                                                &fld2_offset, &title)) {
                        return -1;  // 解析另一个字段元组失败,返回异常
                    }
                    /* Raise an exception if it overlaps */
                    // 如果两个字段有重叠部分,抛出异常
                    if (fld_offset < fld2_offset + fld2_dtype->elsize &&
                                fld2_offset < fld_offset + fld_dtype->elsize) {
                        PyErr_SetString(PyExc_TypeError,
                                "Cannot create a NumPy dtype with overlapping "
                                "object fields");
                        return -1;
                    }
                }
            }
        }
    }

    /* It passed all the overlap tests */
    // 所有重叠检查通过,返回成功
    return 0;
}
/*
 * 创建一个空的 Python 字典对象,用于存储字段信息
 */
PyObject *fields = PyDict_New();
if (fields == NULL) {
    // 如果内存分配失败,返回内存错误异常
    return (PyArray_Descr *)PyErr_NoMemory();
}

/*
 * 使用 PyMapping_GetItemString 函数获取字典对象中的 "names" 键对应的值
 * 这支持 dictproxy 对象的访问方式
 */
PyObject *names = PyMapping_GetItemString(obj, "names");
if (names == NULL) {
    // 如果找不到 "names" 键,清理已分配的资源并调用 _convert_from_field_dict 函数处理
    Py_DECREF(fields);
    PyErr_Clear();  // 清理异常状态
    return _convert_from_field_dict(obj, align);
}

/*
 * 使用 PyMapping_GetItemString 函数获取字典对象中的 "formats" 键对应的值
 */
PyObject *descrs = PyMapping_GetItemString(obj, "formats");
if (descrs == NULL) {
    // 如果找不到 "formats" 键,清理已分配的资源并调用 _convert_from_field_dict 函数处理
    Py_DECREF(fields);
    PyErr_Clear();  // 清理异常状态
    Py_DECREF(names);  // 清理已获取的 "names" 值
    return _convert_from_field_dict(obj, align);
}

// 获取 names 列表的长度
int n = PyObject_Length(names);

/*
 * 使用 PyMapping_GetItemString 函数获取字典对象中的 "offsets" 键对应的值
 * 如果找不到该键,清理异常状态
 */
PyObject *offsets = PyMapping_GetItemString(obj, "offsets");
if (!offsets) {
    PyErr_Clear();  // 清理异常状态
}

/*
 * 使用 PyMapping_GetItemString 函数获取字典对象中的 "titles" 键对应的值
 * 如果找不到该键,清理异常状态
 */
PyObject *titles = PyMapping_GetItemString(obj, "titles");
if (!titles) {
    PyErr_Clear();  // 清理异常状态
}
    # 检查 'names', 'formats', 'offsets', 'titles' 四个字典的长度是否一致,若不一致则抛出异常并跳转到失败处理标签
    if ((n > PyObject_Length(descrs))
        || (offsets && (n > PyObject_Length(offsets)))
        || (titles && (n > PyObject_Length(titles)))) {
        PyErr_SetString(PyExc_ValueError,
                "'names', 'formats', 'offsets', and 'titles' dict "
                "entries must have the same length");
        goto fail;
    }

    """
    如果字典中有属性 'aligned',则根据其值覆盖 align 变量的设置,如果该属性不存在则忽略。
    如果 'aligned' 的值不是 True 或 False,则抛出异常并跳转到失败处理标签。
    """
    PyObject *tmp = PyMapping_GetItemString(obj, "aligned");
    if (tmp == NULL) {
        PyErr_Clear();
    } else {
        if (tmp == Py_True) {
            align = 1;
        }
        else if (tmp != Py_False) {
            Py_DECREF(tmp);
            PyErr_SetString(PyExc_ValueError,
                    "NumPy dtype descriptor includes 'aligned' entry, "
                    "but its value is neither True nor False");
            goto fail;
        }
        Py_DECREF(tmp);
    }

    """
    对于包含字段的数据类型,需要使用 Python C API 进行字段访问。
    """
    char dtypeflags = NPY_NEEDS_PYAPI;
    int totalsize = 0;
    int maxalign = 1;
    int has_out_of_order_fields = 0;
    }

    """
    创建一个新的 NumPy 数据类型描述符对象 new,并根据情况设置对齐方式和大小。
    如果创建失败,则跳转到失败处理标签。
    """
    _PyArray_LegacyDescr *new = (_PyArray_LegacyDescr *)PyArray_DescrNewFromType(NPY_VOID);
    if (new == NULL) {
        goto fail;
    }
    if (maxalign > 1) {
        totalsize = NPY_NEXT_ALIGNED_OFFSET(totalsize, maxalign);
    }
    if (align) {
        new->alignment = maxalign;
    }
    new->elsize = totalsize;
    if (!PyTuple_Check(names)) {
        Py_SETREF(names, PySequence_Tuple(names));
        if (names == NULL) {
            Py_DECREF(new);
            goto fail;
        }
    }
    new->names = names;
    new->fields = fields;
    new->flags = dtypeflags;
    """
    new 对象接管了 names 和 fields 对象的 DECREF 责任。
    """
    names = NULL;
    fields = NULL;

    """
    如果字段不是按顺序排列,并且存在 OBJECT 类型,则需要验证 OBJECT 类型是否与其他类型重叠。
    """
    if (has_out_of_order_fields && PyDataType_REFCHK((PyArray_Descr *)new)) {
        if (_validate_object_field_overlap(new) < 0) {
            Py_DECREF(new);
            goto fail;
        }
    }

    """
    对于结构化数组,设置 NPY_ALIGNED_STRUCT 标志位。
    """
    if (align) {
        new->flags |= NPY_ALIGNED_STRUCT;
    }

    """
    如果提供了 'itemsize' 属性,则覆盖 new 的 itemsize 值。
    """
    tmp = PyMapping_GetItemString(obj, "itemsize");
    if (tmp == NULL) {
        PyErr_Clear();
    } else {
        // 从临时对象 tmp 中获取 itemsize,并转换为整数类型
        int itemsize = (int)PyArray_PyIntAsInt(tmp);
        // 释放 tmp 对象的引用计数
        Py_DECREF(tmp);
        // 如果转换出错,则释放新创建的 PyArray_Descr 对象并跳转到失败标签
        if (error_converting(itemsize)) {
            Py_DECREF(new);
            goto fail;
        }
        /* 确保 itemsize 不会比 new->elsize 小 */
        if (itemsize < new->elsize) {
            // 抛出数值错误异常,提示无法将 itemsize 覆盖为比 new->elsize 更小的值
            PyErr_Format(PyExc_ValueError,
                    "NumPy dtype descriptor requires %d bytes, "
                    "cannot override to smaller itemsize of %d",
                    new->elsize, itemsize);
            Py_DECREF(new);
            goto fail;
        }
        /* 如果设置了 align,确保对齐方式能整除 itemsize */
        if (align && new->alignment > 0 && itemsize % new->alignment != 0) {
            // 抛出数值错误异常,提示指定的对齐方式无法整除指定的 itemsize
            PyErr_Format(PyExc_ValueError,
                    "NumPy dtype descriptor requires alignment of %d bytes, "
                    "which is not divisible into the specified itemsize %d",
                    new->alignment, itemsize);
            Py_DECREF(new);
            goto fail;
        }
        /* 设置新的 itemsize */
        new->elsize = itemsize;
    }

    /* 如果提供了 metadata,则添加到新创建的 PyArray_Descr 对象中 */
    PyObject *metadata = PyMapping_GetItemString(obj, "metadata");

    if (metadata == NULL) {
        // 清除当前异常状态
        PyErr_Clear();
    }
    else if (new->metadata == NULL) {
        // 如果当前 metadata 为空,则将其赋值给新创建的 PyArray_Descr 对象的 metadata
        new->metadata = metadata;
    }
    else {
        // 将 metadata 合并到 new->metadata 中,如果出错则释放新创建的 PyArray_Descr 对象并跳转到失败标签
        int ret = PyDict_Merge(new->metadata, metadata, 0);
        Py_DECREF(metadata);
        if (ret < 0) {
            Py_DECREF(new);
            goto fail;
        }
    }

    // 释放其他的临时对象的引用计数
    Py_XDECREF(fields);
    Py_XDECREF(names);
    Py_XDECREF(descrs);
    Py_XDECREF(offsets);
    Py_XDECREF(titles);
    // 返回新创建的 PyArray_Descr 对象的指针
    return (PyArray_Descr *)new;

 fail:
    // 如果发生失败,则释放所有的临时对象的引用计数并返回 NULL
    Py_XDECREF(fields);
    Py_XDECREF(names);
    Py_XDECREF(descrs);
    Py_XDECREF(offsets);
    Py_XDECREF(titles);
    return NULL;
/*NUMPY_API*/
// 定义一个函数 PyArray_DescrNewFromType,根据给定的类型编号创建并返回一个新的描述符对象
NPY_NO_EXPORT PyArray_Descr *
PyArray_DescrNewFromType(int type_num)
{
    // 声明两个指向 PyArray_Descr 结构的指针变量
    PyArray_Descr *old;
    PyArray_Descr *new;

    // 调用 PyArray_DescrFromType 函数获取给定类型编号对应的描述符对象
    old = PyArray_DescrFromType(type_num);
    // 如果获取失败,返回空指针
    if (old == NULL) {
        return NULL;
    }
    // 使用获取到的描述符对象创建一个新的描述符对象
    new = PyArray_DescrNew(old);
    // 减少旧描述符对象的引用计数
    Py_DECREF(old);
    // 返回新创建的描述符对象
    return new;
}

/*NUMPY_API
 * 从对象获取类型编号,如果是 None,则返回 NULL
 */
// 定义一个函数 PyArray_DescrConverter2,用于从对象中获取类型描述符
NPY_NO_EXPORT int
PyArray_DescrConverter2(PyObject *obj, PyArray_Descr **at)
{
    // 如果传入的对象是 None,则将输出的描述符指针设置为 NULL,并返回成功状态码
    if (obj == Py_None) {
        *at = NULL;
        return NPY_SUCCEED;
    }
    else {
        // 否则调用 PyArray_DescrConverter 函数来获取描述符
        return PyArray_DescrConverter(obj, at);
    }
}

/**
 * 检查描述符是否是传统的“灵活”DType实例,这通常是指未附加到数组的实例,比如长度为0的字符串或没有单位的日期时间。
 * 这些实例应该已经被大部分废弃,通常只表示大多数“dtype”参数的 DType 类。
 *
 * TODO: 这个函数最终应该收到弃用警告并被移除。
 *
 * @param descr 要检查的描述符
 * @return 如果不是具体的 dtype 实例则返回 1,否则返回 0
 */
// 定义一个静态函数 descr_is_legacy_parametric_instance,用于检查描述符是否是传统的“灵活”DType实例
static int
descr_is_legacy_parametric_instance(PyArray_Descr *descr,
                                    PyArray_DTypeMeta *DType)
{
    // 如果不是传统的 DType 实例,则返回 0
    if (!NPY_DT_is_legacy(DType)) {
        return 0;
    }

    // 如果是无大小的数据类型,则返回 1
    if (PyDataType_ISUNSIZED(descr)) {
        return 1;
    }
    // 如果是带有通用时间单位的灵活描述符
    if (PyDataType_ISDATETIME(descr)) {
        // 获取日期时间元数据
        PyArray_DatetimeMetaData *meta;
        meta = get_datetime_metadata_from_dtype(descr);
        // 如果基本单位是通用的,则返回 1
        if (meta->base == NPY_FR_GENERIC) {
            return 1;
        }
    }
    // 否则返回 0
    return 0;
}

/**
 * 给定一个描述符(dtype 实例),处理将传统的灵活“无大小”描述符转换为它们的 DType。返回的 DType 和描述符都可以为空(如果输入为空)。但是当设置描述符时总是设置 DType。
 *
 * @param dtype 要处理的描述符
 * @param out_descr 输出的描述符指针
 * @param out_DType 输出的 DType 指针
 * @return 成功返回 0,失败返回 -1
 */
// 定义一个函数 PyArray_ExtractDTypeAndDescriptor,用于从描述符中提取 DType 和描述符
NPY_NO_EXPORT int
PyArray_ExtractDTypeAndDescriptor(PyArray_Descr *dtype,
        PyArray_Descr **out_descr, PyArray_DTypeMeta **out_DType)
{
    // 将输出的 DType 和描述符初始化为空
    *out_DType = NULL;
    *out_descr = NULL;

    // 如果输入的描述符不为空
    if (dtype != NULL) {
        // 获取描述符对应的 DType
        *out_DType = NPY_DTYPE(dtype);
        // 增加 DType 的引用计数
        Py_INCREF(*out_DType);
        // 如果描述符不是传统的灵活参数化实例
        if (!descr_is_legacy_parametric_instance((PyArray_Descr *)dtype,
                                                    *out_DType)) {
            // 设置输出的描述符
            *out_descr = (PyArray_Descr *)dtype;
            // 增加描述符的引用计数
            Py_INCREF(*out_descr);
        }
    }
    // 返回成功状态码
    return 0;
}
/**
 * Convert a Python object to a numpy dtype descriptor or class.
 * This function fills the npy_dtype_info structure with the result
 * on success.
 *
 * @param obj Python object representing a dtype instance (descriptor) or DType class.
 * @param[out] dt_info Pointer to npy_dtype_info struct where the dtype class and
 *                    dtype/descriptor instance are filled. If `obj` is None, both
 *                    fields will be NULL. On error, both will remain NULL.
 * @return NPY_SUCCEED (1) on success, NPY_FAIL (0) on failure.
 */
NPY_NO_EXPORT int
PyArray_DTypeOrDescrConverterRequired(PyObject *obj, npy_dtype_info *dt_info)
{
    /*
     * Allow dtype classes pass, this could also be generalized to at least
     * some scalar types (right now most of these give instances or)
     */
    
    dt_info->dtype = NULL; // Initialize dtype to NULL
    dt_info->descr = NULL; // Initialize descr to NULL

    if (PyObject_TypeCheck(obj, &PyArrayDTypeMeta_Type)) {
        if (obj == (PyObject *)&PyArrayDescr_Type) {
            PyErr_SetString(PyExc_TypeError,
                            "Cannot convert np.dtype into a dtype.");
            return NPY_FAIL; // Return failure if trying to convert np.dtype into dtype
        }
        Py_INCREF(obj); // Increment reference count to obj
        dt_info->dtype = (PyArray_DTypeMeta *)obj; // Set dtype to DTypeMeta object
        dt_info->descr = NULL; // Leave descriptor as NULL
        return NPY_SUCCEED; // Return success
    }

    PyArray_Descr *descr;
    if (PyArray_DescrConverter(obj, &descr) != NPY_SUCCEED) {
        return NPY_FAIL; // Return failure if conversion fails
    }

    /*
     * The above converts e.g. "S" or "S0" to the prototype instance, we make
     * it behave the same as the DType.  This is not fully correct, "S0" should
     * be considered an instance with actual 0 length.
     * TODO: It would be nice to fix that eventually.
     */
    
    int res = PyArray_ExtractDTypeAndDescriptor(
                descr, &dt_info->descr, &dt_info->dtype); // Extract dtype and descriptor
    Py_DECREF(descr); // Decrement reference count to descr
    if (res < 0) {
        return NPY_FAIL; // Return failure if extraction fails
    }
    return NPY_SUCCEED; // Return success
}

/**
 * Optional converter function that initializes npy_dtype_info struct to NULL
 * if obj is None, otherwise delegates to PyArray_DTypeOrDescrConverterRequired.
 *
 * @param obj Python object representing a dtype instance (descriptor) or DType class,
 *            or None.
 * @param[out] dt_info Pointer to npy_dtype_info struct where the dtype class and
 *                    dtype/descriptor instance are filled. If `obj` is None, both
 *                    fields will be NULL. On error, both will remain NULL.
 * @return NPY_SUCCEED (1) if obj is None, or the result of
 *         PyArray_DTypeOrDescrConverterRequired.
 */
NPY_NO_EXPORT int
PyArray_DTypeOrDescrConverterOptional(PyObject *obj, npy_dtype_info *dt_info)
{
    if (obj == Py_None) {
        /* caller must have initialized for the optional version */
        return NPY_SUCCEED; // Return success if obj is None
    }
    return PyArray_DTypeOrDescrConverterRequired(obj, dt_info); // Delegate to required converter otherwise
}

/**
 * Given a DType class, returns the default instance (descriptor). This
 * checks for a `singleton` first and only calls the `default_descr` function
 * if necessary.
 *
 * @param DType DType class object from which to retrieve the default instance.
 * @return PyArray_Descr * Pointer to the default instance descriptor on success,
 *         NULL on failure.
 */
NPY_NO_EXPORT PyArray_Descr *
PyArray_GetDefaultDescr(PyArray_DTypeMeta *DType)
{
    if (DType->singleton != NULL) {
        Py_INCREF(DType->singleton); // Increment reference count to singleton
        return DType->singleton; // Return the singleton if available
    }
    return NPY_DT_CALL_default_descr(DType); // Call default_descr function to retrieve default descriptor
}

/**
 * Get a dtype instance from a python type.
 *
 * @param obj Python object representing a type.
 * @return PyArray_Descr * Pointer to the dtype instance on success,
 *         NULL on failure.
 */
static PyArray_Descr *
_convert_from_type(PyObject *obj) {
    PyTypeObject *typ = (PyTypeObject*)obj;

    if (PyType_IsSubtype(typ, &PyGenericArrType_Type)) {
        return PyArray_DescrFromTypeObject(obj); // Return descriptor from type object if it's a subtype of PyGenericArrType_Type
    }
    else if (typ == &PyLong_Type) {
        return PyArray_DescrFromType(NPY_INTP); // Return descriptor from NPY_INTP if the type is PyLong_Type
    }

    // More conditions can be added here for other types if needed

    /* If obj doesn't match any condition, return NULL */
    return NULL;
}
    else if (typ == &PyFloat_Type) {
        // 如果对象类型为 Python 的 float 类型,则返回对应的双精度浮点类型描述符
        return PyArray_DescrFromType(NPY_DOUBLE);
    }
    else if (typ == &PyComplex_Type) {
        // 如果对象类型为 Python 的 complex 类型,则返回对应的双精度复数类型描述符
        return PyArray_DescrFromType(NPY_CDOUBLE);
    }
    else if (typ == &PyBool_Type) {
        // 如果对象类型为 Python 的 bool 类型,则返回对应的布尔类型描述符
        return PyArray_DescrFromType(NPY_BOOL);
    }
    else if (typ == &PyBytes_Type) {
        /*
         * TODO: This should be deprecated, and have special handling for
         *       dtype=bytes/"S" in coercion: It should not rely on "S0".
         */
        // 如果对象类型为 Python 的 bytes 类型,则返回对应的字符串类型描述符
        return PyArray_DescrFromType(NPY_STRING);
    }
    else if (typ == &PyUnicode_Type) {
        /*
         * TODO: This should be deprecated, and have special handling for
         *       dtype=str/"U" in coercion: It should not rely on "U0".
         */
        // 如果对象类型为 Python 的 unicode 类型,则返回对应的 Unicode 字符串类型描述符
        return PyArray_DescrFromType(NPY_UNICODE);
    }
    else if (typ == &PyMemoryView_Type) {
        // 如果对象类型为 Python 的 memoryview 类型,则返回对应的 void 类型描述符
        return PyArray_DescrFromType(NPY_VOID);
    }
    else if (typ == &PyBaseObject_Type) {
        // 如果对象类型为 Python 的基本对象类型,则返回对应的对象类型描述符
        return PyArray_DescrFromType(NPY_OBJECT);
    }
    else {
        // 尝试从对象的 dtype 属性转换描述符
        PyArray_Descr *ret = _try_convert_from_dtype_attr(obj);
        // 如果成功转换,则返回转换后的描述符
        if ((PyObject *)ret != Py_NotImplemented) {
            return ret;
        }
        Py_DECREF(ret);

        /*
         * Note: this comes after _try_convert_from_dtype_attr because the ctypes
         * type might override the dtype if numpy does not otherwise
         * support it.
         */
        // 尝试从 ctypes 类型尝试转换描述符
        ret = _try_convert_from_ctypes_type(typ);
        // 如果成功转换,则返回转换后的描述符
        if ((PyObject *)ret != Py_NotImplemented) {
            return ret;
        }
        Py_DECREF(ret);

        /*
         * All other classes are treated as object. This can be convenient
         * to convey an intention of using it for a specific python type
         * and possibly allow converting to a new type-specific dtype in the future. It may make sense to
         * only allow this only within `dtype=...` keyword argument context
         * in the future.
         */
        // 所有其他类型都视为对象类型,返回对象类型描述符
        return PyArray_DescrFromType(NPY_OBJECT);
    }
/* 
   static PyArray_Descr * _convert_from_any(PyObject *obj, int align)
   {
       /* default */
       if (obj == Py_None) {
           // 如果输入是 Py_None,则返回默认类型的数组描述符
           return PyArray_DescrFromType(NPY_DEFAULT_TYPE);
       }
       else if (PyArray_DescrCheck(obj)) {
           // 如果输入是数组描述符,则增加其引用计数并返回
           PyArray_Descr *ret = (PyArray_Descr *)obj;
           Py_INCREF(ret);
           return ret;
       }
       else if (PyType_Check(obj)) {
           // 如果输入是类型对象,则调用 _convert_from_type 处理
           return _convert_from_type(obj);
       }
       /* or a typecode string */
       else if (PyBytes_Check(obj)) {
           /* Allow bytes format strings: convert to unicode */
           // 如果输入是字节对象,则将其转换为 Unicode 对象
           PyObject *obj2 = PyUnicode_FromEncodedObject(obj, NULL, NULL);
           if (obj2 == NULL) {
               /* Convert the exception into a TypeError */
               // 如果转换过程中出现异常,将其转换为 TypeError 并返回空指针
               if (PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)) {
                   PyErr_SetString(PyExc_TypeError,
                           "data type not understood");
               }
               return NULL;
           }
           // 调用 _convert_from_str 处理 Unicode 对象
           PyArray_Descr *ret = _convert_from_str(obj2, align);
           Py_DECREF(obj2);
           return ret;
       }
       else if (PyUnicode_Check(obj)) {
           // 如果输入是 Unicode 对象,则调用 _convert_from_str 处理
           return _convert_from_str(obj, align);
       }
       else if (PyTuple_Check(obj)) {
           /* or a tuple */
           // 如果输入是元组,则尝试递归地处理
           if (Py_EnterRecursiveCall(
                   " while trying to convert the given data type from"
                   " a tuple object" ) != 0) {
               return NULL;
           }
           // 调用 _convert_from_tuple 处理元组对象
           PyArray_Descr *ret = _convert_from_tuple(obj, align);
           Py_LeaveRecursiveCall();
           return ret;
       }
       else if (PyList_Check(obj)) {
           /* or a list */
           // 如果输入是列表,则尝试递归地处理
           if (Py_EnterRecursiveCall(
                   " while trying to convert the given data type from"
                   " a list object" ) != 0) {
               return NULL;
           }
           // 调用 _convert_from_array_descr 处理列表对象
           PyArray_Descr *ret = _convert_from_array_descr(obj, align);
           Py_LeaveRecursiveCall();
           return ret;
       }
       else if (PyDict_Check(obj) || PyDictProxy_Check(obj)) {
           /* or a dictionary */
           // 如果输入是字典或字典代理对象,则尝试递归地处理
           if (Py_EnterRecursiveCall(
                   " while trying to convert the given data type from"
                   " a dict object" ) != 0) {
               return NULL;
           }
           // 调用 _convert_from_dict 处理字典对象
           PyArray_Descr *ret = _convert_from_dict(obj, align);
           Py_LeaveRecursiveCall();
           return ret;
       }
       else if (PyArray_Check(obj)) {
           // 如果输入是数组对象,则设置一个类型错误并返回空指针
           PyErr_SetString(PyExc_TypeError, "Cannot construct a dtype from an array");
           return NULL;
       }
   }
*/
    else {
        // 尝试从对象获取描述符
        PyArray_Descr *ret = _try_convert_from_dtype_attr(obj);
        // 如果返回的不是 Py_NotImplemented 对象,则直接返回该描述符
        if ((PyObject *)ret != Py_NotImplemented) {
            return ret;
        }
        // 减少描述符的引用计数
        Py_DECREF(ret);

        /*
         * 注意: 这里放在 _try_convert_from_dtype_attr 后面,
         * 因为 ctypes 类型可能会覆盖 dtype,如果 numpy 没有其他支持的话。
         */
        // 尝试从 ctypes 类型转换
        ret = _try_convert_from_ctypes_type(Py_TYPE(obj));
        // 如果返回的不是 Py_NotImplemented 对象,则直接返回该描述符
        if ((PyObject *)ret != Py_NotImplemented) {
            return ret;
        }
        // 减少描述符的引用计数
        Py_DECREF(ret);

        // 抛出类型错误异常,指示无法解释 obj 作为数据类型
        PyErr_Format(PyExc_TypeError, "Cannot interpret '%R' as a data type", obj);
        // 返回空指针表示失败
        return NULL;
    }
/*NUMPY_API
 * Get typenum from an object -- None goes to NPY_DEFAULT_TYPE
 * This function takes a Python object representing a type and converts it
 * to a the correct PyArray_Descr * structure to describe the type.
 *
 * Many objects can be used to represent a data-type which in NumPy is
 * quite a flexible concept.
 *
 * This is the central code that converts Python objects to
 * Type-descriptor objects that are used throughout numpy.
 *
 * Returns a new reference in *at, but the returned should not be
 * modified as it may be one of the canonical immutable objects or
 * a reference to the input obj.
 */
NPY_NO_EXPORT int
PyArray_DescrConverter(PyObject *obj, PyArray_Descr **at)
{
    // 调用 _convert_from_any 函数将 Python 对象转换为 PyArray_Descr 结构体
    *at = _convert_from_any(obj, 0);
    // 返回转换结果是否成功的状态
    return (*at) ? NPY_SUCCEED : NPY_FAIL;
}

/** Convert a bytestring specification into a dtype */
static PyArray_Descr *
_convert_from_str(PyObject *obj, int align)
{
    /* Check for a string typecode. */
    // 将 Python 对象转换为 UTF-8 字符串及其长度
    Py_ssize_t len = 0;
    char const *type = PyUnicode_AsUTF8AndSize(obj, &len);
    if (type == NULL) {
        return NULL;
    }

    /* Empty string is invalid */
    // 空字符串不合法
    if (len == 0) {
        goto fail;
    }

    /* check for commas present or first (or second) element a digit */
    // 检查字符串中是否包含逗号,或者第一个(或第二个)字符是否是数字
    if (_check_for_commastring(type, len)) {
        // 如果满足条件,调用 _convert_from_commastring 函数进行转换
        return _convert_from_commastring(obj, align);
    }

    /* Process the endian character. '|' is replaced by '='*/
    // 处理字节顺序字符,将 '|' 替换为 '='
    char endian = '=';
    switch (type[0]) {
        case '>':
        case '<':
        case '=':
            endian = type[0];
            ++type;
            --len;
            break;

        case '|':
            endian = '=';
            ++type;
            --len;
            break;
    }

    /* Just an endian character is invalid */
    // 只有字节顺序字符是无效的情况
    if (len == 0) {
        goto fail;
    }

    /* Check for datetime format */
    // 检查是否为日期时间格式
    if (is_datetime_typestr(type, len)) {
        // 如果是日期时间格式,调用 parse_dtype_from_datetime_typestr 函数解析数据类型
        PyArray_Descr *ret = parse_dtype_from_datetime_typestr(type, len);
        if (ret == NULL) {
            return NULL;
        }
        /* ret has byte order '=' at this point */
        // 在此处,ret 的字节顺序为 '='
        if (!PyArray_ISNBO(endian)) {
            ret->byteorder = endian;
        }
        return ret;
    }

    int check_num = NPY_NOTYPE + 10;
    int elsize = 0;
    /* A typecode like 'd' */
    // 类似于 'd' 的类型码
    if (len == 1) {
        /* Python byte string characters are unsigned */
        // Python 字节字符串的字符是无符号的
        check_num = (unsigned char) type[0];
    }
    /* Possibly a kind + size like 'f8' but also could be 'bool' */
    else {
        // 指向类型字符串中类型字符后的结束位置
        char *typeend = NULL;
        // 类型码
        int kind;

        /* 尝试解析整数,并确保其为字符串的剩余部分 */
        errno = 0;
        // 将类型字符串的第一个字符后面的内容解析为长整型数值
        long result = strtol(type + 1, &typeend, 10);
        // 检查是否有解析发生
        npy_bool some_parsing_happened = !(type == typeend);
        // 检查是否整个字符串被消耗
        npy_bool entire_string_consumed = *typeend == '\0';
        // 检查解析是否成功
        npy_bool parsing_succeeded =
                (errno == 0) && some_parsing_happened && entire_string_consumed;
        // 确保数值不会溢出或为负数
        if (result > INT_MAX || result < 0) {
            goto fail;
        }

        // 将解析的整数值作为元素大小
        elsize = (int)result;


        // 如果解析成功并且类型字符串被完全消耗
        if (parsing_succeeded && typeend - type == len) {

            // 获取类型码的第一个字符
            kind = type[0];
            // 根据类型码进行相应处理
            switch (kind) {
                case NPY_STRINGLTR:
                    // 字符串类型处理
                    check_num = NPY_STRING;
                    break;

                case NPY_DEPRECATED_STRINGLTR2:
                    // 已弃用的字符串类型处理
                    if (DEPRECATE("Data type alias 'a' was deprecated in NumPy 2.0. "
                                  "Use the 'S' alias instead.") < 0) {
                        return NULL;
                    }
                    check_num = NPY_STRING;
                    break;

                /*
                 * 当指定 UNICODE 的长度时,
                 * 给出的是字符数以匹配 STRING 接口。
                 * 每个字符可能超过一个字节,itemsize 必须是字节数。
                 */
                case NPY_UNICODELTR:
                    // UNICODE 类型处理
                    check_num = NPY_UNICODE;
                    // 将元素大小左移两位(相当于乘以 4)
                    elsize <<= 2;
                    break;

                case NPY_VOIDLTR:
                    // VOID 类型处理
                    check_num = NPY_VOID;
                    break;

                default:
                    // 如果元素大小为 0,则默认为 NPY_NOTYPE + 10
                    if (elsize == 0) {
                        check_num = NPY_NOTYPE + 10;
                    }
                    // 支持通用处理 c8、i4、f8 等
                    else {
                        check_num = PyArray_TypestrConvert(elsize, kind);
                        // 如果转换失败,默认加 10
                        if (check_num == NPY_NOTYPE) {
                            check_num += 10;
                        }
                        // 重置元素大小为 0
                        elsize = 0;
                    }
            }
        }
        // 如果解析成功但是类型字符串未被完全消耗,则失败
        else if (parsing_succeeded) {
            goto fail;
        }
    }

    // 如果发生了 Python 异常,则失败
    if (PyErr_Occurred()) {
        goto fail;
    }

    // 返回描述符对象
    PyArray_Descr *ret;
    # 检查 `check_num` 是否为 `NPY_NOTYPE + 10` 或者根据该数字获取对应的数组描述符
    if ((check_num == NPY_NOTYPE + 10) ||
            (ret = PyArray_DescrFromType(check_num)) == NULL) {
        PyErr_Clear();
        # 清除异常状态,检查对象是否在 `typeDict` 中注册
        /* Now check to see if the object is registered in typeDict */
        if (typeDict == NULL) {
            # 如果 `typeDict` 为 NULL,则跳转到 `fail` 标签处
            goto fail;
        }
        # 从 `typeDict` 中获取键为 `obj` 的项,返回 NULL 表示未找到,可能出错时返回 NULL
        PyObject *item = PyDict_GetItemWithError(typeDict, obj);
        if (item == NULL) {
            # 如果出现了异常,则返回 NULL
            if (PyErr_Occurred()) {
                return NULL;
            }
            # 如果 `type` 等于特定字符串,则抛出特定类型的异常并返回 NULL
            if (
                strcmp(type, "int0") == 0 || strcmp(type, "uint0") == 0 ||
                strcmp(type, "void0") == 0 || strcmp(type, "object0") == 0 ||
                strcmp(type, "str0") == 0 || strcmp(type, "bytes0") == 0 ||
                strcmp(type, "bool8") == 0
            ) {
                PyErr_Format(PyExc_TypeError,
                        "Alias %R was removed in NumPy 2.0. Use a name "
                        "without a digit at the end.", obj);
                return NULL;
            }
            # 否则跳转到 `fail` 标签处
            goto fail;
        }

        # 如果 `type` 等于 "a",则发出关于该别名被弃用的警告信息,如果发生错误则返回 NULL
        if (strcmp(type, "a") == 0) {
            if (DEPRECATE("Data type alias 'a' was deprecated in NumPy 2.0. "
                          "Use the 'S' alias instead.") < 0) {
                return NULL;
            }
        }

        /*
         * 可能仅仅调度到 `_convert_from_type`,但是不知道用户可能注入到 `np.typeDict` 中的内容。
         * Probably only ever dispatches to `_convert_from_type`, but who
         * knows what users are injecting into `np.typeDict`.
         */
        # 返回使用 `_convert_from_any` 函数将 `item` 转换为所需类型的结果,带有对齐参数 `align`
        return _convert_from_any(item, align);
    }

    # 如果返回的数组描述符 `ret` 是无大小的并且其元素大小不等于 `elsize`,则替换描述符的大小为 `elsize`
    if (PyDataType_ISUNSIZED(ret) && ret->elsize != elsize) {
        PyArray_DESCR_REPLACE(ret);
        # 如果替换后 `ret` 为 NULL,则返回 NULL
        if (ret == NULL) {
            return NULL;
        }
        # 设置 `ret` 的元素大小为 `elsize`
        ret->elsize = elsize;
    }
    # 如果 `endian` 不等于 '=' 且 `endian` 是本机字节序,则设置 `endian` 为 '='
    if (endian != '=' && PyArray_ISNBO(endian)) {
        endian = '=';
    }
    # 如果 `endian` 不等于 '=' 且 `ret` 的字节顺序不是 '|' 且不等于 `endian`,则替换描述符的字节顺序为 `endian`
    if (endian != '=' && ret->byteorder != '|' && ret->byteorder != endian) {
        PyArray_DESCR_REPLACE(ret);
        # 如果替换后 `ret` 为 NULL,则返回 NULL
        if (ret == NULL) {
            return NULL;
        }
        # 设置 `ret` 的字节顺序为 `endian`
        ret->byteorder = endian;
    }
    # 返回最终确定的数组描述符 `ret`
    return ret;
/*
 * 如果对象的数据类型不被理解,抛出类型错误并返回空指针。
 * 这里使用 PyErr_Format 来格式化错误信息,%R 代表对象 obj。
 */
fail:
    PyErr_Format(PyExc_TypeError, "data type %R not understood", obj);
    return NULL;
}

/** Array Descr Objects for dynamic types **/

/*
 * 这里定义了一些静态的 PyArray_Descr 对象,对应基本的内置类型。
 * 这些对象在适当的情况下应当进行 DECREF 和 INCREF 操作。
 * 如果在引用计数上出现错误,可能会导致尝试对这些内置对象进行解引用,从而引发问题。
 *
 * 这种方法允许我们使用引用计数来管理所有 PyArray_Descr 对象
 * (无论它们是静态分配还是动态分配的)。
 */

/*NUMPY_API
 * base 不能为空
 */
NPY_NO_EXPORT PyArray_Descr *
PyArray_DescrNew(PyArray_Descr *base_descr)
{
    if (!PyDataType_ISLEGACY(base_descr)) {
        /* 
         * 主要用途是对字符串进行变异,因此在新风格 DTypes 上可能禁止此操作是合理的。
         * 如果 base_descr 不是旧风格的数据类型,则抛出运行时错误。
         */
        PyErr_SetString(PyExc_RuntimeError,
            "cannot use `PyArray_DescrNew` on new style DTypes.");
        return NULL;
    }
    _PyArray_LegacyDescr *base = (_PyArray_LegacyDescr *)base_descr;
    _PyArray_LegacyDescr *newdescr = PyObject_New(_PyArray_LegacyDescr, Py_TYPE(base));

    if (newdescr == NULL) {
        return NULL;
    }
    /* 不复制 PyObject_HEAD 部分 */
    memcpy((char *)newdescr + sizeof(PyObject),
           (char *)base + sizeof(PyObject),
           sizeof(_PyArray_LegacyDescr) - sizeof(PyObject));

    /*
     * c_metadata 使用值拥有模型,需要克隆它(基本上是深拷贝,
     * 但 auxdata 克隆函数仍具有一定的灵活性),以便新的 PyArray_Descr 对象拥有数据的拷贝。
     * 如果 base->c_metadata 不为空,则克隆它,避免多次释放内存。
     */
    if (base->c_metadata != NULL) {
        newdescr->c_metadata = NPY_AUXDATA_CLONE(base->c_metadata);
        if (newdescr->c_metadata == NULL) {
            PyErr_NoMemory();
            /* 错误处理,释放 newdescr,避免内存泄漏 */
            Py_DECREF(newdescr);
            return NULL;
        }
    }

    if (newdescr->fields == Py_None) {
        newdescr->fields = NULL;
    }
    Py_XINCREF(newdescr->fields);
    Py_XINCREF(newdescr->names);
    if (newdescr->subarray) {
        newdescr->subarray = PyArray_malloc(sizeof(PyArray_ArrayDescr));
        if (newdescr->subarray == NULL) {
            Py_DECREF(newdescr);
            return (PyArray_Descr *)PyErr_NoMemory();
        }
        memcpy(newdescr->subarray, base->subarray, sizeof(PyArray_ArrayDescr));
        Py_INCREF(newdescr->subarray->shape);
        Py_INCREF(newdescr->subarray->base);
    }
    Py_XINCREF(newdescr->typeobj);
    Py_XINCREF(newdescr->metadata);
    newdescr->hash = -1;

    return (PyArray_Descr *)newdescr;
}

/*
 * 如果没有引用计数问题,通常不应对内置类型调用此函数。
 */
static void
arraydescr_dealloc(PyArray_Descr *self)
{
    # 释放 self 对象中的 typeobj 引用,如果存在的话
    Py_XDECREF(self->typeobj);
    
    # 如果 self 不是传统的 dtype(即非传统 dtype),则必须没有 fields 等属性
    if (!PyDataType_ISLEGACY(self)) {
        # 调用 self 对象的类型的 tp_free 方法释放对象内存
        Py_TYPE(self)->tp_free((PyObject *)self);
        return;
    }
    
    # 将 self 转换为 _PyArray_LegacyDescr 类型
    _PyArray_LegacyDescr *lself = (_PyArray_LegacyDescr *)self;

    # 如果 lself 的 fields 属性为 Py_None,表示出现了引用计数错误
    if (lself->fields == Py_None) {
        # 打印错误信息到 stderr,显示出错的 dtype 编号和类型
        fprintf(stderr, "*** Reference count error detected: "
                "an attempt was made to deallocate the dtype %d (%c) ***\n",
                self->type_num, self->type);
        # 断言程序停止,以便调试
        assert(0);
        # 增加 self 的引用计数两次(此处可能是出于调试目的,确保不被释放)
        Py_INCREF(self);
        Py_INCREF(self);
        return;
    }
    
    # 释放 lself 的 names 和 fields 属性的引用计数
    Py_XDECREF(lself->names);
    Py_XDECREF(lself->fields);
    
    # 如果 lself 的 subarray 存在,则释放其 shape 和 base 属性,最后释放 subarray 本身
    if (lself->subarray) {
        Py_XDECREF(lself->subarray->shape);
        Py_DECREF(lself->subarray->base);
        PyArray_free(lself->subarray);
    }
    
    # 释放 lself 的 metadata 属性的引用计数
    Py_XDECREF(lself->metadata);
    
    # 释放 lself 的 c_metadata 指针,并将其设置为 NULL
    NPY_AUXDATA_FREE(lself->c_metadata);
    lself->c_metadata = NULL;
    
    # 最终调用 self 对象的类型的 tp_free 方法释放对象内存
    Py_TYPE(self)->tp_free((PyObject *)self);
/*
 * we need to be careful about setting attributes because these
 * objects are pointed to by arrays that depend on them for interpreting
 * data.  Currently no attributes of data-type objects can be set
 * directly except names.
 */
static PyMemberDef arraydescr_members[] = {
    {"type",
        T_OBJECT, offsetof(PyArray_Descr, typeobj), READONLY, NULL},  // 成员变量:类型对象
    {"kind",
        T_CHAR, offsetof(PyArray_Descr, kind), READONLY, NULL},  // 成员变量:数据类型的种类
    {"char",
        T_CHAR, offsetof(PyArray_Descr, type), READONLY, NULL},  // 成员变量:数据类型的字符表示
    {"num",
        T_INT, offsetof(PyArray_Descr, type_num), READONLY, NULL},  // 成员变量:数据类型的数值编码
    {"byteorder",
        T_CHAR, offsetof(PyArray_Descr, byteorder), READONLY, NULL},  // 成员变量:字节顺序
    {"itemsize",
        T_PYSSIZET, offsetof(PyArray_Descr, elsize), READONLY, NULL},  // 成员变量:数据类型的字节大小
    {"alignment",
        T_PYSSIZET, offsetof(PyArray_Descr, alignment), READONLY, NULL},  // 成员变量:数据类型的对齐方式
    {"flags",
#if NPY_ULONGLONG == NPY_UINT64
        T_ULONGLONG, offsetof(PyArray_Descr, flags), READONLY, NULL},  // 成员变量:数据类型的标志位
#else
    #error Assuming long long is 64bit, if not replace with getter function.
#endif
    {NULL, 0, 0, 0, NULL},  // 结束标记
};

static PyObject *
arraydescr_subdescr_get(PyArray_Descr *self, void *NPY_UNUSED(ignored))
{
    if (!PyDataType_HASSUBARRAY(self)) {
        Py_RETURN_NONE;  // 如果没有子数组,返回 None
    }
    return Py_BuildValue("OO",
            PyDataType_SUBARRAY(self)->base, PyDataType_SUBARRAY(self)->shape);  // 构建返回值元组,包含子数组的基础类型和形状
}

NPY_NO_EXPORT PyObject *
arraydescr_protocol_typestr_get(PyArray_Descr *self, void *NPY_UNUSED(ignored))
{
    char basic_ = self->kind;  // 获取数据类型的基础类型字符
    char endian = self->byteorder;  // 获取数据类型的字节顺序
    int size = self->elsize;  // 获取数据类型的字节大小
    PyObject *ret;

    if (endian == '=') {  // 如果字节顺序为 '='
        endian = '<';  // 将字节顺序设为 '<'
        if (!PyArray_IsNativeByteOrder(endian)) {  // 如果不是本地字节顺序
            endian = '>';  // 将字节顺序设为 '>'
        }
    }
    if (self->type_num == NPY_UNICODE) {  // 如果数据类型为 Unicode
        size >>= 2;  // 右移两位,相当于除以 4
    }
    if (self->type_num == NPY_OBJECT) {  // 如果数据类型为对象
        ret = PyUnicode_FromFormat("%c%c", endian, basic_);  // 格式化生成 Unicode 对象
    }
    else {  // 否则
        ret = PyUnicode_FromFormat("%c%c%d", endian, basic_, size);  // 格式化生成 Unicode 对象,包含数据类型大小
    }
    if (ret == NULL) {  // 如果生成失败
        return NULL;  // 返回空指针
    }

    if (PyDataType_ISDATETIME(self)) {  // 如果是日期时间类型
        PyArray_DatetimeMetaData *meta;
        meta = get_datetime_metadata_from_dtype(self);  // 获取日期时间元数据
        if (meta == NULL) {  // 如果获取失败
            Py_DECREF(ret);  // 释放生成的 Unicode 对象
            return NULL;  // 返回空指针
        }
        PyObject *umeta = metastr_to_unicode(meta, 0);  // 将元数据转换为 Unicode 字符串
        if (umeta == NULL) {  // 如果转换失败
            Py_DECREF(ret);  // 释放生成的 Unicode 对象
            return NULL;  // 返回空指针
        }

        Py_SETREF(ret, PyUnicode_Concat(ret, umeta));  // 连接两个 Unicode 对象
        Py_DECREF(umeta);  // 释放 umeta 对象的引用
    }
    return ret;  // 返回 Unicode 对象
}

static PyObject *
arraydescr_name_get(PyArray_Descr *self, void *NPY_UNUSED(ignored))
{
    /* let python handle this */  // 让 Python 处理这部分
    PyObject *_numpy_dtype;
    PyObject *res;
    _numpy_dtype = PyImport_ImportModule("numpy._core._dtype");  // 导入 numpy._core._dtype 模块
    if (_numpy_dtype == NULL) {  // 如果导入失败
        return NULL;  // 返回空指针
    }
    res = PyObject_CallMethod(_numpy_dtype, "_name_get", "O", self);  // 调用 _numpy_dtype 对象的 _name_get 方法
    Py_DECREF(_numpy_dtype);  // 释放 _numpy_dtype 对象的引用
    return res;  // 返回调用结果
}

static PyObject *
/*
 * 返回一个数组描述符的基本数据类型,如果没有子数组,则增加引用计数并返回自身。
 */
PyObject *
arraydescr_base_get(PyArray_Descr *self, void *NPY_UNUSED(ignored))
{
    if (!PyDataType_HASSUBARRAY(self)) {
        Py_INCREF(self);
        return (PyObject *)self;
    }
    Py_INCREF(PyDataType_SUBARRAY(self)->base);
    return (PyObject *)(PyDataType_SUBARRAY(self)->base);
}

/*
 * 返回数组描述符的形状,如果没有子数组,则返回空元组。
 * 如果有子数组,确保形状是元组并增加其引用计数后返回。
 */
static PyObject *
arraydescr_shape_get(PyArray_Descr *self, void *NPY_UNUSED(ignored))
{
    if (!PyDataType_HASSUBARRAY(self)) {
        return PyTuple_New(0);
    }
    assert(PyTuple_Check(PyDataType_SUBARRAY(self)->shape));
    Py_INCREF(PyDataType_SUBARRAY(self)->shape);
    return PyDataType_SUBARRAY(self)->shape;
}

/*
 * 返回数组描述符的维度数。如果没有子数组,则返回长整型 0。
 * 否则,获取子数组的形状元组的大小并作为长整型返回。
 */
static PyObject *
arraydescr_ndim_get(PyArray_Descr *self, void *NPY_UNUSED(ignored))
{
    Py_ssize_t ndim;

    if (!PyDataType_HASSUBARRAY(self)) {
        return PyLong_FromLong(0);
    }

    /*
     * PyTuple_Size 具有内置检查,确保参数为元组
     */
    ndim = PyTuple_Size(PyDataType_SUBARRAY(self)->shape);
    return PyLong_FromLong(ndim);
}

/*
 * 返回数组描述符的协议描述符。如果没有字段,返回默认描述符。
 * 否则,调用 _numpy_internal 模块的 _array_descr 方法获取描述符。
 */
NPY_NO_EXPORT PyObject *
arraydescr_protocol_descr_get(PyArray_Descr *self, void *NPY_UNUSED(ignored))
{
    PyObject *dobj, *res;
    PyObject *_numpy_internal;

    if (!PyDataType_HASFIELDS(self)) {
        /* 获取默认描述符 */
        dobj = PyTuple_New(2);
        if (dobj == NULL) {
            return NULL;
        }
        PyTuple_SET_ITEM(dobj, 0, PyUnicode_FromString(""));
        PyTuple_SET_ITEM(dobj, 1, arraydescr_protocol_typestr_get(self, NULL));
        res = PyList_New(1);
        if (res == NULL) {
            Py_DECREF(dobj);
            return NULL;
        }
        PyList_SET_ITEM(res, 0, dobj);
        return res;
    }

    _numpy_internal = PyImport_ImportModule("numpy._core._internal");
    if (_numpy_internal == NULL) {
        return NULL;
    }
    res = PyObject_CallMethod(_numpy_internal, "_array_descr", "O", self);
    Py_DECREF(_numpy_internal);
    return res;
}

/*
 * 返回数组描述符是否为内建类型(返回 1)或用户定义数据类型描述符(返回 2)。
 * 如果既不是,返回 0。
 */
static PyObject *
arraydescr_isbuiltin_get(PyArray_Descr *self, void *NPY_UNUSED(ignored))
{
    long val;
    val = 0;
    if (PyDataType_FIELDS(self) == Py_None) {
        val = 1;
    }
    if (PyTypeNum_ISUSERDEF(self->type_num)) {
        val = 2;
    }
    return PyLong_FromLong(val);
}

/*
 * 检查数组描述符是否为本地字节顺序。
 * 如果没有字段,则检查字节顺序是否为本地顺序。
 * 否则,遍历字段字典,逐个检查是否都是本地顺序。
 */
static int
_arraydescr_isnative(PyArray_Descr *self)
{
    if (!PyDataType_HASFIELDS(self)) {
        return PyArray_ISNBO(self->byteorder);
    }
    else {
        PyObject *key, *value, *title = NULL;
        PyArray_Descr *new;
        int offset;
        Py_ssize_t pos = 0;
        while (PyDict_Next(PyDataType_FIELDS(self), &pos, &key, &value)) {
            if (NPY_TITLE_KEY(key, value)) {
                continue;
            }
            if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset, &title)) {
                return -1;
            }
            if (!_arraydescr_isnative(new)) {
                return 0;
            }
        }
    }
    return 1;
}
/*
 * 返回 Py_True 如果该数据类型描述符具有本机字节顺序且没有定义字段,
 * 或者如果所有子字段都具有本机字节顺序且定义了字段。
 */
static PyObject *
arraydescr_isnative_get(PyArray_Descr *self, void *NPY_UNUSED(ignored))
{
    PyObject *ret;
    int retval;
    // 调用内部函数检查是否具有本机字节顺序
    retval = _arraydescr_isnative(self);
    if (retval == -1) {
        return NULL;
    }
    // 根据返回值设置 ret 为 Py_True 或 Py_False
    ret = retval ? Py_True : Py_False;
    Py_INCREF(ret);
    return ret;
}

/*
 * 返回 Py_True 如果 self 的标志中包含 NPY_ALIGNED_STRUCT,
 * 否则返回 Py_False。
 */
static PyObject *
arraydescr_isalignedstruct_get(PyArray_Descr *self, void *NPY_UNUSED(ignored))
{
    PyObject *ret;
    // 检查是否标志中包含 NPY_ALIGNED_STRUCT
    ret = (self->flags & NPY_ALIGNED_STRUCT) ? Py_True : Py_False;
    Py_INCREF(ret);
    return ret;
}

/*
 * 如果 self 没有字段定义,则返回 Py_None;
 * 否则返回一个指向字段字典的 PyDictProxy 对象。
 */
static PyObject *
arraydescr_fields_get(PyArray_Descr *self, void *NPY_UNUSED(ignored))
{
    if (!PyDataType_HASFIELDS(self)) {
        // 如果没有字段定义,则返回 Py_None
        Py_RETURN_NONE;
    }
    // 返回字段字典的 PyDictProxy 对象
    return PyDictProxy_New(PyDataType_FIELDS(self));
}

/*
 * 如果 self 的 metadata 为 NULL,则返回 Py_None;
 * 否则返回一个指向 metadata 字典的 PyDictProxy 对象。
 */
static PyObject *
arraydescr_metadata_get(PyArray_Descr *self, void *NPY_UNUSED(ignored))
{
    if (self->metadata == NULL) {
        // 如果 metadata 为 NULL,则返回 Py_None
        Py_RETURN_NONE;
    }
    // 返回 metadata 字典的 PyDictProxy 对象
    return PyDictProxy_New(self->metadata);
}

/*
 * 如果 PyDataType_FLAGCHK(self, NPY_ITEM_HASOBJECT) 为真,则返回 Py_True;
 * 否则返回 Py_False。
 */
static PyObject *
arraydescr_hasobject_get(PyArray_Descr *self, void *NPY_UNUSED(ignored))
{
    if (PyDataType_FLAGCHK(self, NPY_ITEM_HASOBJECT)) {
        // 如果标志中包含 NPY_ITEM_HASOBJECT,则返回 Py_True
        Py_RETURN_TRUE;
    }
    else {
        // 否则返回 Py_False
        Py_RETURN_FALSE;
    }
}

/*
 * 如果 self 没有字段定义,则返回 Py_None;
 * 否则返回一个指向字段名元组的引用,并增加其引用计数。
 */
static PyObject *
arraydescr_names_get(PyArray_Descr *self, void *NPY_UNUSED(ignored))
{
    if (!PyDataType_HASFIELDS(self)) {
        // 如果没有字段定义,则返回 Py_None
        Py_RETURN_NONE;
    }
    // 增加字段名元组的引用计数并返回其引用
    Py_INCREF(PyDataType_NAMES(self));
    return PyDataType_NAMES(self);
}

/*
 * 设置 self 的字段名。
 * val 是新的字段名序列,应该是一个字符串序列。
 * 返回 -1 表示出错,0 表示成功。
 */
static int
arraydescr_names_set(
        _PyArray_LegacyDescr *self, PyObject *val, void *NPY_UNUSED(ignored))
{
    int N = 0;
    int i;
    PyObject *new_names;
    PyObject *new_fields;

    if (val == NULL) {
        PyErr_SetString(PyExc_AttributeError,
                "Cannot delete dtype names attribute");
        return -1;
    }
    if (!PyDataType_HASFIELDS(self)) {
        PyErr_SetString(PyExc_ValueError,
                "there are no fields defined");
        return -1;
    }

    /*
     * FIXME
     *
     * This deprecation has been temporarily removed for the NumPy 1.7
     * release. It should be re-added after the 1.7 branch is done,
     * and a convenience API to replace the typical use-cases for
     * mutable names should be implemented.
     *
     * if (DEPRECATE("Setting NumPy dtype names is deprecated, the dtype "
     *                "will become immutable in a future version") < 0) {
     *     return -1;
     * }
     */

    // 获取当前字段名元组的大小
    N = PyTuple_GET_SIZE(self->names);
    // 检查 val 是否为序列且长度与字段名元组相等
    if (!PySequence_Check(val) || PyObject_Size((PyObject *)val) != N) {
        /* 应该是 TypeError,但是这段代码应该被弃用。 */
        PyErr_Format(PyExc_ValueError,
                "must replace all names at once with a sequence of length %d",
                N);
        return -1;
    }
    /* 确保所有条目都是字符串 */
    // 省略部分代码,处理确保所有条目是字符串的逻辑
}
    for (i = 0; i < N; i++) {
        PyObject *item;
        int valid;
        // 获取序列 `val` 中第 `i` 个元素
        item = PySequence_GetItem(val, i);
        // 检查 `item` 是否为 Unicode 字符串
        valid = PyUnicode_Check(item);
        // 如果 `item` 不是有效的 Unicode 字符串
        if (!valid) {
            // 抛出值错误异常,指明非字符串类型的名称
            PyErr_Format(PyExc_ValueError,
                    "item #%d of names is of type %s and not string",
                    i, Py_TYPE(item)->tp_name);
            Py_DECREF(item); // 释放 `item` 的引用
            return -1; // 返回错误标志
        }
        Py_DECREF(item); // 释放 `item` 的引用
    }
    /* Invalidate cached hash value */
    // 将缓存的哈希值设为无效值 `-1`
    self->hash = -1;
    /* Update dictionary keys in fields */
    // 将序列 `val` 转换为元组 `new_names`
    new_names = PySequence_Tuple(val);
    // 如果转换失败,返回错误标志
    if (new_names == NULL) {
        return -1;
    }
    // 创建新的空字典 `new_fields`
    new_fields = PyDict_New();
    // 如果创建失败,释放 `new_names` 并返回错误标志
    if (new_fields == NULL) {
        Py_DECREF(new_names);
        return -1;
    }
    for (i = 0; i < N; i++) {
        PyObject *key;
        PyObject *item;
        PyObject *new_key;
        int ret;
        // 获取 `self->names` 元组中第 `i` 个元素作为键 `key`
        key = PyTuple_GET_ITEM(self->names, i);
        // 在 `self->fields` 字典中查找键为 `key` 的项,引用计数不增加
        /* Borrowed references to item and new_key */
        item = PyDict_GetItemWithError(self->fields, key);
        // 如果未找到 `key` 对应的项且没有错误发生
        if (item == NULL) {
            if (!PyErr_Occurred()) {
                // 抛出内部调用错误异常
                PyErr_BadInternalCall();
            }
            Py_DECREF(new_names); // 释放 `new_names` 的引用
            Py_DECREF(new_fields); // 释放 `new_fields` 的引用
            return -1; // 返回错误标志
        }
        // 获取 `new_names` 元组中第 `i` 个元素作为新键 `new_key`
        new_key = PyTuple_GET_ITEM(new_names, i);
        // 检查 `new_fields` 字典中是否包含 `new_key`
        ret = PyDict_Contains(new_fields, new_key);
        // 如果检查过程中发生错误,释放 `new_names` 和 `new_fields` 的引用并返回错误标志
        if (ret < 0) {
            Py_DECREF(new_names);
            Py_DECREF(new_fields);
            return -1;
        }
        // 如果 `new_fields` 中已经包含 `new_key`,抛出值错误异常
        else if (ret != 0) {
            PyErr_SetString(PyExc_ValueError, "Duplicate field names given.");
            Py_DECREF(new_names);
            Py_DECREF(new_fields);
            return -1;
        }
        // 将 `item` 与 `new_key` 添加到 `new_fields` 字典中
        if (PyDict_SetItem(new_fields, new_key, item) < 0) {
            Py_DECREF(new_names);
            Py_DECREF(new_fields);
            return -1;
        }
    }

    /* Replace names */
    // 释放旧的 `self->names` 引用,将 `new_names` 赋值给 `self->names`
    Py_DECREF(self->names);
    self->names = new_names;

    /* Replace fields */
    // 释放旧的 `self->fields` 引用,将 `new_fields` 赋值给 `self->fields`
    Py_DECREF(self->fields);
    self->fields = new_fields;

    return 0;
# 定义一个静态的属性获取器和设置器的列表,用于描述数组描述符对象的各种属性
static PyGetSetDef arraydescr_getsets[] = {
    # 子数据类型描述符的获取器,使用arraydescr_subdescr_get函数
    {"subdtype",
        (getter)arraydescr_subdescr_get,
        NULL, NULL, NULL},
    # 描述符的获取器,使用arraydescr_protocol_descr_get函数
    {"descr",
        (getter)arraydescr_protocol_descr_get,
        NULL, NULL, NULL},
    # 字符串形式的类型描述符的获取器,使用arraydescr_protocol_typestr_get函数
    {"str",
        (getter)arraydescr_protocol_typestr_get,
        NULL, NULL, NULL},
    # 名称的获取器,使用arraydescr_name_get函数
    {"name",
        (getter)arraydescr_name_get,
        NULL, NULL, NULL},
    # 基本类型的获取器,使用arraydescr_base_get函数
    {"base",
        (getter)arraydescr_base_get,
        NULL, NULL, NULL},
    # 数组形状的获取器,使用arraydescr_shape_get函数
    {"shape",
        (getter)arraydescr_shape_get,
        NULL, NULL, NULL},
    # 数组维度的获取器,使用arraydescr_ndim_get函数
    {"ndim",
        (getter)arraydescr_ndim_get,
        NULL, NULL, NULL},
    # 是否为内建类型的获取器,使用arraydescr_isbuiltin_get函数
    {"isbuiltin",
        (getter)arraydescr_isbuiltin_get,
        NULL, NULL, NULL},
    # 是否为本地字节序的获取器,使用arraydescr_isnative_get函数
    {"isnative",
        (getter)arraydescr_isnative_get,
        NULL, NULL, NULL},
    # 是否为对齐结构的获取器,使用arraydescr_isalignedstruct_get函数
    {"isalignedstruct",
        (getter)arraydescr_isalignedstruct_get,
        NULL, NULL, NULL},
    # 字段的获取器,使用arraydescr_fields_get函数
    {"fields",
        (getter)arraydescr_fields_get,
        NULL, NULL, NULL},
    # 元数据的获取器,使用arraydescr_metadata_get函数
    {"metadata",
        (getter)arraydescr_metadata_get,
        NULL, NULL, NULL},
    # 名称列表的获取器和设置器,使用arraydescr_names_get和arraydescr_names_set函数
    {"names",
        (getter)arraydescr_names_get,
        (setter)arraydescr_names_set,
        NULL, NULL},
    # 是否含有对象的获取器,使用arraydescr_hasobject_get函数
    {"hasobject",
        (getter)arraydescr_hasobject_get,
        NULL, NULL, NULL},
    # 结束符号,没有getter、setter和doc
    {NULL, NULL, NULL, NULL, NULL},
};
    if (subtype != &PyArrayDescr_Type) {
        # 检查 subtype 是否不是 PyArrayDescr_Type 类型的对象
        if (Py_TYPE(subtype) == &PyArrayDTypeMeta_Type &&
                (NPY_DT_SLOTS((PyArray_DTypeMeta *)subtype)) != NULL &&
                !NPY_DT_is_legacy((PyArray_DTypeMeta *)subtype) &&
                subtype->tp_new != PyArrayDescr_Type.tp_new) {
            '''
            如果 subtype 是 PyArrayDTypeMeta_Type 类型的对象,并且满足以下条件:
            - NPY_DT_SLOTS((PyArray_DTypeMeta *)subtype) 不为 NULL
            - 不是遗留的 dtype
            - subtype 的 tp_new 方法不等于 PyArrayDescr_Type.tp_new 方法
            
            则认为其是一个正确初始化的用户自定义 dtype。分配内存并尽可能初始化主要部分。
            TODO: 这可能应该是一个用户函数,并强制执行诸如正确设置 `elsize` 等规则。
            TODO: 这是实验性的 API!
            '''
            # 将 subtype 转换为 PyArray_DTypeMeta 类型
            PyArray_DTypeMeta *DType = (PyArray_DTypeMeta *)subtype;
            # 分配一个 PyArray_Descr 对象
            PyArray_Descr *descr = (PyArray_Descr *)subtype->tp_alloc(subtype, 0);
            if (descr == 0) {
                # 分配内存失败,抛出内存错误异常
                PyErr_NoMemory();
                return NULL;
            }
            # 增加对 scalar_type 的引用计数
            Py_XINCREF(DType->scalar_type);
            # 设置 descr 对象的 typeobj 和 type_num 属性
            descr->typeobj = DType->scalar_type;
            descr->type_num = DType->type_num;
            # 设置 descr 对象的 flags、byteorder、elsize 和 hash 属性
            descr->flags = NPY_USE_GETITEM|NPY_USE_SETITEM;
            descr->byteorder = '|';  # 如果 DType 使用了 byteorder,则允许其覆盖
            descr->elsize = -1;  # 初始化为无效值
            descr->hash = -1;
            # 返回 PyArray_Descr 对象的 PyObject 表示
            return (PyObject *)descr;
        }
        '''
        若程序流执行到这里,表明 subtype 类型不符合预期:
        DTypeMeta 类应该防止这种情况发生。
        '''
        # 抛出系统错误异常,指示不应该从 np.dtype.__new__() 继承
        PyErr_Format(PyExc_SystemError,
                "'%S' must not inherit np.dtype.__new__(). User DTypes should "
                "currently call `PyArrayDescr_Type.tp_new` from their new.",
                subtype);
        return NULL;
    }

    PyObject *odescr, *metadata=NULL;
    PyArray_Descr *conv;
    npy_bool align = NPY_FALSE;
    npy_bool copy = NPY_FALSE;
    npy_bool copied = NPY_FALSE;

    static char *kwlist[] = {"dtype", "align", "copy", "metadata", NULL};

    # 解析输入参数,以及可选的 align、copy 和 metadata 参数
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&O&O!:dtype", kwlist,
                &odescr,
                PyArray_BoolConverter, &align,
                PyArray_BoolConverter, &copy,
                &PyDict_Type, &metadata)) {
        return NULL;
    }

    # 将 odescr 转换为 PyArray_Descr 对象,使用 align 参数
    conv = _convert_from_any(odescr, align);
    if (conv == NULL) {
        return NULL;
    }

    # 如果需要复制且 conv 不是一个复制
    if (copy && PyDataType_FIELDS(conv) == Py_None) {
        # 替换 conv 的描述符
        PyArray_DESCR_REPLACE(conv);
        if (conv == NULL) {
            return NULL;
        }
        # 设置 copied 标志为 True
        copied = NPY_TRUE;
    }
    // 如果 metadata 不为空
    if ((metadata != NULL)) {
        // 检查 conv 不是旧式数据类型
        if (!PyDataType_ISLEGACY(conv)) {
            // 抛出类型错误异常,因为不能给新式数据类型附加元数据
            PyErr_SetString(PyExc_TypeError,
                    "cannot attach metadata to new style DType");
            // 释放 conv 的引用计数,并返回空指针
            Py_DECREF(conv);
            return NULL;
        }
        /*
         * We need to be sure to make a new copy of the data-type and any
         * underlying dictionary
         */
        // 如果还没有复制过数据类型描述符
        if (!copied) {
            // 替换 conv 的数据类型描述符为一个新的副本
            PyArray_DESCR_REPLACE(conv);
            // 如果替换后 conv 为空,则返回空指针
            if (conv == NULL) {
                return NULL;
            }
            // 设置复制标记为真
            copied = NPY_TRUE;
        }
        // 将 conv 强制转换为旧式数据类型描述符类型
        _PyArray_LegacyDescr *lconv = (_PyArray_LegacyDescr *)conv;
        // 如果旧式描述符已经有元数据
        if ((lconv->metadata != NULL)) {
            /*
             * Make a copy of the metadata before merging with the
             * input metadata so that this data-type descriptor has
             * its own copy
             */
            /* Save a reference */
            // 保存原元数据的引用
            odescr = lconv->metadata;
            // 创建元数据的新副本
            lconv->metadata = PyDict_Copy(odescr);
            // 减少原元数据的引用计数
            Py_DECREF(odescr);

            /*
             * Update conv->metadata with anything new in metadata
             * keyword, but do not over-write anything already there
             */
            // 将输入的 metadata 合并到 conv->metadata 中,不覆盖已有的内容
            if (PyDict_Merge(lconv->metadata, metadata, 0) != 0) {
                // 合并失败时,释放 conv 的引用计数,并返回空指针
                Py_DECREF(conv);
                return NULL;
            }
        }
        else {
            /* Make a copy of the input dictionary */
            // 创建输入字典 metadata 的新副本,并赋给 lconv->metadata
            lconv->metadata = PyDict_Copy(metadata);
        }
    }

    // 返回 conv 强制转换为 PyObject 指针类型
    return (PyObject *)conv;
/*
 * Return a tuple of
 * (cleaned metadata dictionary, tuple with (str, num))
 */
static PyObject *
_get_pickleabletype_from_datetime_metadata(PyArray_Descr *dtype)
{
    PyObject *ret, *dt_tuple;
    PyArray_DatetimeMetaData *meta;

    /* Create the 2-item tuple to return */
    ret = PyTuple_New(2);
    if (ret == NULL) {
        return NULL;
    }

    /* Store the metadata dictionary */
    if (dtype->metadata != NULL) {
        Py_INCREF(dtype->metadata);  // 增加元数据字典的引用计数
        PyTuple_SET_ITEM(ret, 0, dtype->metadata);  // 将元数据字典设置为返回元组的第一个元素
    } else {
        PyTuple_SET_ITEM(ret, 0, PyDict_New());  // 如果元数据为空,则创建一个新的空字典
    }

    /* Convert the datetime metadata into a tuple */
    meta = get_datetime_metadata_from_dtype(dtype);  // 获取日期时间的元数据
    if (meta == NULL) {
        Py_DECREF(ret);  // 如果获取失败,释放返回的元组
        return NULL;
    }
    /* Use a 4-tuple that numpy 1.6 knows how to unpickle */
    dt_tuple = PyTuple_New(4);  // 创建一个包含四个元素的元组
    if (dt_tuple == NULL) {
        Py_DECREF(ret);  // 如果创建失败,释放返回的元组
        return NULL;
    }
    PyTuple_SET_ITEM(dt_tuple, 0,
            PyBytes_FromString(_datetime_strings[meta->base]));  // 设置元组的第一个元素为日期时间基础的字节串
    PyTuple_SET_ITEM(dt_tuple, 1,
            PyLong_FromLong(meta->num));  // 设置元组的第二个元素为日期时间的数值
    PyTuple_SET_ITEM(dt_tuple, 2,
            PyLong_FromLong(1));  // 设置元组的第三个元素为整数1
    PyTuple_SET_ITEM(dt_tuple, 3,
            PyLong_FromLong(1));  // 设置元组的第四个元素为整数1

    PyTuple_SET_ITEM(ret, 1, dt_tuple);  // 将日期时间元组设置为返回元组的第二个元素

    return ret;  // 返回包含元数据字典和日期时间元组的元组
}

/*
 * return a tuple of (callable object, args, state).
 *
 * TODO: This method needs to change so that unpickling doesn't
 *       use __setstate__. This is required for the dtype
 *       to be an immutable object.
 */
static PyObject *
arraydescr_reduce(PyArray_Descr *self, PyObject *NPY_UNUSED(args))
{
    /*
     * version number of this pickle type. Increment if we need to
     * change the format. Be sure to handle the old versions in
     * arraydescr_setstate.
    */
    const int version = 4;  // 定义当前 pickle 格式的版本号为4
    PyObject *ret, *mod, *obj;
    PyObject *state;
    char endian;
    int elsize, alignment;

    ret = PyTuple_New(3);  // 创建一个包含三个元素的元组作为返回值
    if (ret == NULL) {
        return NULL;
    }
    mod = PyImport_ImportModule("numpy._core._multiarray_umath");  // 导入 numpy 的 umath 模块
    if (mod == NULL) {
        Py_DECREF(ret);  // 如果导入模块失败,释放返回的元组
        return NULL;
    }
    obj = PyObject_GetAttr(mod, npy_interned_str.dtype);  // 获取 umath 模块中的 dtype 属性对象
    Py_DECREF(mod);  // 释放导入的 umath 模块对象
    if (obj == NULL) {
        Py_DECREF(ret);  // 如果获取 dtype 属性失败,释放返回的元组
        return NULL;
    }
    PyTuple_SET_ITEM(ret, 0, obj);  // 将获取的 dtype 属性对象设置为返回元组的第一个元素
    if (PyTypeNum_ISUSERDEF(self->type_num)
            || ((self->type_num == NPY_VOID
                    && self->typeobj != &PyVoidArrType_Type))) {
        obj = (PyObject *)self->typeobj;  // 如果类型为用户定义或者是 VOID 类型但不是 PyVoidArrType_Type 类型
        Py_INCREF(obj);  // 增加类型对象的引用计数
    }
    else if (!NPY_DT_is_legacy(NPY_DTYPE(self))) {
        PyErr_SetString(PyExc_RuntimeError,
                "Custom dtypes cannot use the default pickle implementation "
                "for NumPy dtypes. Add a custom pickle implementation to the "
                "DType to avoid this error");  // 如果不是遗留的类型且不是用户定义的类型,抛出运行时错误
        return NULL;
    }
    else {
        // 获取元素大小
        elsize = self->elsize;
        // 如果是Unicode类型,则右移两位(相当于除以4),因为Unicode字符大小为4字节
        if (self->type_num == NPY_UNICODE) {
            elsize >>= 2;
        }
        // 根据kind和elsize创建Python Unicode对象
        obj = PyUnicode_FromFormat("%c%d",self->kind, elsize);
    }
    // 将obj、Py_False和Py_True打包成一个元组,放入ret元组的第二个位置
    PyTuple_SET_ITEM(ret, 1, Py_BuildValue("(NOO)", obj, Py_False, Py_True));

    /*
     * 现在返回至少包含字节顺序、子数组和字段的状态
     */
    // 获取字节顺序
    endian = self->byteorder;
    // 如果字节顺序为平台本地顺序
    if (endian == '=') {
        endian = '<';
        // 如果不是本地字节顺序,设为大端字节顺序
        if (!PyArray_IsNativeByteOrder(endian)) {
            endian = '>';
        }
    }
    // 如果是日期时间类型
    if (PyDataType_ISDATETIME(self)) {
        PyObject *newobj;
        // 创建一个包含9个元素的元组
        state = PyTuple_New(9);
        // 设置第一个元素为版本号的长整型对象
        PyTuple_SET_ITEM(state, 0, PyLong_FromLong(version));
        /*
         * newobj是Python元数据字典和日期时间信息(str, num)的元组
         */
        // 从日期时间元数据获取可序列化的类型对象
        newobj = _get_pickleabletype_from_datetime_metadata(self);
        // 如果获取失败,释放资源并返回空
        if (newobj == NULL) {
            Py_DECREF(state);
            Py_DECREF(ret);
            return NULL;
        }
        // 设置第九个元素为newobj
        PyTuple_SET_ITEM(state, 8, newobj);
    }
    // 如果有元数据
    else if (self->metadata) {
        // 创建一个包含9个元素的元组
        state = PyTuple_New(9);
        // 设置第一个元素为版本号的长整型对象
        PyTuple_SET_ITEM(state, 0, PyLong_FromLong(version));
        // 增加元数据的引用计数并设置为第九个元素
        Py_INCREF(self->metadata);
        PyTuple_SET_ITEM(state, 8, self->metadata);
    }
    // 否则使用版本3的pickle格式
    else { /* Use version 3 pickle format */
        // 创建一个包含8个元素的元组
        state = PyTuple_New(8);
        // 设置第一个元素为版本号3的长整型对象
        PyTuple_SET_ITEM(state, 0, PyLong_FromLong(3));
    }

    // 设置元组state的第一个元素为字节顺序的Unicode对象
    PyTuple_SET_ITEM(state, 1, PyUnicode_FromFormat("%c", endian));
    // 获取数组描述子描述信息
    PyTuple_SET_ITEM(state, 2, arraydescr_subdescr_get(self, NULL));
    // 如果有字段信息
    if (PyDataType_HASFIELDS(self)) {
        // 增加字段名和字段数据的引用计数,并设置为第三和第四个元素
        Py_INCREF(PyDataType_NAMES(self));
        Py_INCREF(PyDataType_FIELDS(self));
        PyTuple_SET_ITEM(state, 3, PyDataType_NAMES(self));
        PyTuple_SET_ITEM(state, 4, PyDataType_FIELDS(self));
    }
    // 如果没有字段信息
    else {
        // 设置第三和第四个元素为Py_None,并增加引用计数
        PyTuple_SET_ITEM(state, 3, Py_None);
        PyTuple_SET_ITEM(state, 4, Py_None);
        Py_INCREF(Py_None);
        Py_INCREF(Py_None);
    }

    /* 对于扩展类型,还包括elsize和alignment */
    // 如果是扩展类型,设置elsize和alignment
    if (PyTypeNum_ISEXTENDED(self->type_num)) {
        elsize = self->elsize;
        alignment = self->alignment;
    }
    // 否则设置elsize和alignment为-1
    else {
        elsize = -1;
        alignment = -1;
    }
    // 设置第五、六、七个元素为elsize、alignment和flags的长整型对象
    PyTuple_SET_ITEM(state, 5, PyLong_FromLong(elsize));
    PyTuple_SET_ITEM(state, 6, PyLong_FromLong(alignment));
    PyTuple_SET_ITEM(state, 7, PyLong_FromUnsignedLongLong(self->flags));

    // 设置ret元组的第三个元素为state
    PyTuple_SET_ITEM(ret, 2, state);
    // 返回ret元组
    return ret;
/*
 * 返回 NPY_OBJECT_DTYPE_FLAGS,如果此数据类型在设置状态时具有使用对象部分,
 * 因为 hasobject 没有被存储。
 */
static char
_descr_find_object(PyArray_Descr *self)
{
    // 检查数据类型的标志或者类型号是否为 NPY_OBJECT,或者种类是否为 'O'
    if (self->flags
            || self->type_num == NPY_OBJECT
            || self->kind == 'O') {
        return NPY_OBJECT_DTYPE_FLAGS;
    }
    // 如果数据类型有字段
    if (PyDataType_HASFIELDS(self)) {
        PyObject *key, *value, *title = NULL;
        PyArray_Descr *new;
        int offset;
        Py_ssize_t pos = 0;

        // 遍历字段字典
        while (PyDict_Next(PyDataType_FIELDS(self), &pos, &key, &value)) {
            // 跳过特定情况下的标题处理
            if (NPY_TITLE_KEY(key, value)) {
                continue;
            }
            // 解析字段的信息
            if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset, &title)) {
                PyErr_Clear();
                return 0;
            }
            // 递归查找字段的对象部分
            if (_descr_find_object(new)) {
                new->flags = NPY_OBJECT_DTYPE_FLAGS;
                return NPY_OBJECT_DTYPE_FLAGS;
            }
        }
    }
    // 没有找到对象部分,返回 0
    return 0;
}

/*
 * state 至少包含 byteorder、subarray 和 fields,对于 EXTENDED 数组还可以包括
 * elsize 和 alignment。
 */
static PyObject *
arraydescr_setstate(_PyArray_LegacyDescr *self, PyObject *args)
{
    int elsize = -1, alignment = -1;
    int version = 4;
    char endian;
    PyObject *endian_obj;
    PyObject *subarray, *fields, *names = NULL, *metadata=NULL;
    int incref_names = 1;
    int int_dtypeflags = 0;
    npy_uint64 dtypeflags;

    // 如果不是旧版本的数据类型,抛出运行时错误
    if (!PyDataType_ISLEGACY(self)) {
        PyErr_SetString(PyExc_RuntimeError,
                "Cannot unpickle new style DType without custom methods.");
        return NULL;
    }

    // 如果字段为空,返回 None
    if (self->fields == Py_None) {
        Py_RETURN_NONE;
    }

    // 检查参数元组的大小和类型
    if (PyTuple_GET_SIZE(args) != 1
            || !(PyTuple_Check(PyTuple_GET_ITEM(args, 0)))) {
        PyErr_BadInternalCall();
        return NULL;
    }

    // 根据参数元组的大小选择不同的解析方式
    switch (PyTuple_GET_SIZE(PyTuple_GET_ITEM(args,0))) {
    case 9:
        // 解析包含 9 个元素的参数元组
        if (!PyArg_ParseTuple(args, "(iOOOOiiiO):__setstate__",
                    &version, &endian_obj,
                    &subarray, &names, &fields, &elsize,
                    &alignment, &int_dtypeflags, &metadata)) {
            PyErr_Clear();
            return NULL;
        }
        break;
    case 8:
        // 解析包含 8 个元素的参数元组
        if (!PyArg_ParseTuple(args, "(iOOOOiii):__setstate__",
                    &version, &endian_obj,
                    &subarray, &names, &fields, &elsize,
                    &alignment, &int_dtypeflags)) {
            return NULL;
        }
        break;
    case 7:
        // 解析包含 7 个元素的参数元组
        if (!PyArg_ParseTuple(args, "(iOOOOii):__setstate__",
                    &version, &endian_obj,
                    &subarray, &names, &fields, &elsize,
                    &alignment)) {
            return NULL;
        }
        break;
    /* 处理版本号为 6 的情况 */
    case 6:
        /* 解析参数元组,期望格式为 (整数, 对象, 对象, 对象, 整数, 整数) */
        if (!PyArg_ParseTuple(args, "(iOOOii):__setstate__",
                    &version,
                    &endian_obj, &subarray, &fields,
                    &elsize, &alignment)) {
            return NULL;
        }
        break;
    /* 处理版本号为 5 的情况 */
    case 5:
        version = 0;
        /* 解析参数元组,期望格式为 (对象, 对象, 对象, 整数, 整数) */
        if (!PyArg_ParseTuple(args, "(OOOii):__setstate__",
                    &endian_obj, &subarray, &fields, &elsize,
                    &alignment)) {
            return NULL;
        }
        break;
    /* 默认情况下 */
    default:
        /* 抛出错误 */
        if (PyTuple_GET_SIZE(PyTuple_GET_ITEM(args,0)) > 5) {
            /* 如果参数元组的第一个元素的大小大于 5,则尝试将其转换为长整型 */
            version = PyLong_AsLong(PyTuple_GET_ITEM(args, 0));
        }
        else {
            /* 否则版本号为 -1 */
            version = -1;
        }
    }

    /*
     * 如果有新的 pickle 格式需求,增加版本号。
     * 但是应当仍然能够处理旧版本。
     */
    if (version < 0 || version > 4) {
        /* 如果版本号不在有效范围内,抛出相应错误 */
        PyErr_Format(PyExc_ValueError,
                     "can't handle version %d of numpy.dtype pickle",
                     version);
        return NULL;
    }
    /* 使缓存的哈希值无效化 */
    self->hash = -1;

    /* 如果版本号为 1 或 0 */
    if (version == 1 || version == 0) {
        /* 如果 fields 不是 None */
        if (fields != Py_None) {
            PyObject *key, *list;
            key = PyLong_FromLong(-1);
            /* 从 fields 字典中获取值,错误处理方式获取 */
            list = PyDict_GetItemWithError(fields, key);
            if (!list) {
                if (!PyErr_Occurred()) {
                    /* 如果 fields 中缺少它所声称包含的名称 */
                    PyErr_BadInternalCall();
                }
                return NULL;
            }
            /* 增加引用计数并设置 names 为获取到的列表 */
            Py_INCREF(list);
            names = list;
            /* 从 fields 字典中删除 key */
            PyDict_DelItem(fields, key);
            incref_names = 0;
        }
        else {
            /* 否则设置 names 为 None */
            names = Py_None;
        }
    }

    /* 解析 endian 字段 */
    if (PyUnicode_Check(endian_obj) || PyBytes_Check(endian_obj)) {
        PyObject *tmp = NULL;
        char *str;
        Py_ssize_t len;

        /* 如果 endian_obj 是 Unicode 对象,则转换为 ASCII 字符串 */
        if (PyUnicode_Check(endian_obj)) {
            tmp = PyUnicode_AsASCIIString(endian_obj);
            if (tmp == NULL) {
                return NULL;
            }
            endian_obj = tmp;
        }

        /* 获取 endian_obj 的 C 字符串表示和长度 */
        if (PyBytes_AsStringAndSize(endian_obj, &str, &len) < 0) {
            Py_XDECREF(tmp);
            return NULL;
        }
        /* 如果长度不为 1,则抛出错误 */
        if (len != 1) {
            PyErr_SetString(PyExc_ValueError,
                            "endian is not 1-char string in Numpy dtype unpickling");
            Py_XDECREF(tmp);
            return NULL;
        }
        /* 设置 endian 为 str 的第一个字符 */
        endian = str[0];
        Py_XDECREF(tmp);
    }
    else {
        /* 如果 endian_obj 不是字符串,则抛出错误 */
        PyErr_SetString(PyExc_ValueError,
                        "endian is not a string in Numpy dtype unpickling");
        return NULL;
    }

    /* 如果 fields 是 None 而 names 不是,或者 names 是 None 而 fields 不是,则抛出错误 */
    if ((fields == Py_None && names != Py_None) ||
        (names == Py_None && fields != Py_None)) {
        PyErr_Format(PyExc_ValueError,
                "inconsistent fields and names in Numpy dtype unpickling");
        return NULL;
    }
    # 检查 names 是否不是 None 且不是元组类型,如果条件成立,抛出数值错误异常并返回空
    if (names != Py_None && !PyTuple_Check(names)) {
        PyErr_Format(PyExc_ValueError,
                "non-tuple names in Numpy dtype unpickling");
        return NULL;
    }

    # 检查 fields 是否不是 None 且不是字典类型,如果条件成立,抛出数值错误异常并返回空
    if (fields != Py_None && !PyDict_Check(fields)) {
        PyErr_Format(PyExc_ValueError,
                "non-dict fields in Numpy dtype unpickling");
        return NULL;
    }

    # 如果 endian 不是 '|' 并且是本地字节顺序,则将 endian 设置为 '='
    if (endian != '|' && PyArray_IsNativeByteOrder(endian)) {
        endian = '=';
    }
    # 将对象的字节顺序设置为 endian
    self->byteorder = endian;

    # 如果对象已经有子数组,则释放其之前的引用和内存
    if (self->subarray) {
        Py_XDECREF(self->subarray->base);
        Py_XDECREF(self->subarray->shape);
        PyArray_free(self->subarray);
    }
    # 将子数组引用置为空
    self->subarray = NULL;

    # 如果 subarray 不是 None
    if (subarray != Py_None) {
        PyObject *subarray_shape;

        """
         * 确保 subarray[0] 是 ArrayDescr 类型,
         * 并且从 subarray[1] 中获取的 subarray_shape 是由整数组成的元组。
         """
        # 如果 subarray 不是正确的元组结构,抛出数值错误异常并返回空
        if (!(PyTuple_Check(subarray) &&
              PyTuple_Size(subarray) == 2 &&
              PyArray_DescrCheck(PyTuple_GET_ITEM(subarray, 0)))) {
            PyErr_Format(PyExc_ValueError,
                         "incorrect subarray in __setstate__");
            return NULL;
        }
        # 获取 subarray 的第二个元素作为 subarray_shape
        subarray_shape = PyTuple_GET_ITEM(subarray, 1);
        # 如果 subarray_shape 是数字类型,将其转换为长整型
        if (PyNumber_Check(subarray_shape)) {
            PyObject *tmp;
            tmp = PyNumber_Long(subarray_shape);
            if (tmp == NULL) {
                return NULL;
            }
            # 构建一个包含 tmp 的元组,并释放 tmp 的引用
            subarray_shape = Py_BuildValue("(O)", tmp);
            Py_DECREF(tmp);
            if (subarray_shape == NULL) {
                return NULL;
            }
        }
        # 如果 subarray_shape 是由整数组成的元组,增加其引用计数
        else if (_is_tuple_of_integers(subarray_shape)) {
            Py_INCREF(subarray_shape);
        }
        # 否则,抛出数值错误异常并返回空
        else {
            PyErr_Format(PyExc_ValueError,
                         "incorrect subarray shape in __setstate__");
            return NULL;
        }

        # 为 self->subarray 分配内存
        self->subarray = PyArray_malloc(sizeof(PyArray_ArrayDescr));
        if (self->subarray == NULL) {
            return PyErr_NoMemory();
        }
        # 将 subarray 的第一个元素作为 self->subarray->base,并增加其引用计数
        self->subarray->base = (PyArray_Descr *)PyTuple_GET_ITEM(subarray, 0);
        Py_INCREF(self->subarray->base);
        # 将 subarray_shape 赋值给 self->subarray->shape
        self->subarray->shape = subarray_shape;
    }
    if (fields != Py_None) {
        /*
         * 确保字段名的类型适当
         */
        Py_ssize_t i;
        int names_ok = 1;
        PyObject *name;

        // 检查字段名是否都是合适的字符串类型
        for (i = 0; i < PyTuple_GET_SIZE(names); ++i) {
            name = PyTuple_GET_ITEM(names, i);
            if (!PyUnicode_Check(name)) {
                names_ok = 0;
                break;
            }
        }

        // 如果字段名类型全部正确
        if (names_ok) {
            // 释放之前的字段对象,并将新的字段对象赋值给self->fields
            Py_XDECREF(self->fields);
            self->fields = fields;
            // 增加字段对象的引用计数
            Py_INCREF(fields);
            // 释放旧的字段名对象,并将新的字段名对象赋值给self->names
            Py_XDECREF(self->names);
            self->names = names;
            // 如果需要增加字段名对象的引用计数,则增加它
            if (incref_names) {
                Py_INCREF(names);
            }
        }
        else {
            /*
             * 为了支持在Python 3中加载由Python 2生成的pickle文件时的编码问题,
             * 我们需要更宽松地将字段名从字节字符串转换为Unicode。
             */
            PyObject *tmp, *new_name, *field;

            // 创建一个新的空字典对象tmp
            tmp = PyDict_New();
            if (tmp == NULL) {
                return NULL;
            }
            // 释放之前的字段对象,并将新的字段对象赋值给self->fields
            Py_XDECREF(self->fields);
            self->fields = tmp;

            // 创建一个新的空元组对象tmp
            tmp = PyTuple_New(PyTuple_GET_SIZE(names));
            if (tmp == NULL) {
                return NULL;
            }
            // 释放旧的字段名对象,并将新的字段名对象赋值给self->names
            Py_XDECREF(self->names);
            self->names = tmp;

            // 遍历字段名元组,处理每个字段名
            for (i = 0; i < PyTuple_GET_SIZE(names); ++i) {
                name = PyTuple_GET_ITEM(names, i);
                // 在fields字典中查找对应的字段
                field = PyDict_GetItemWithError(fields, name);
                if (!field) {
                    if (!PyErr_Occurred()) {
                        /* fields缺少它声称包含的字段名 */
                        PyErr_BadInternalCall();
                    }
                    return NULL;
                }

                // 如果字段名是Unicode类型,则直接使用它
                if (PyUnicode_Check(name)) {
                    new_name = name;
                    Py_INCREF(new_name);
                }
                else {
                    // 将字节字符串转换为ASCII编码的Unicode对象
                    new_name = PyUnicode_FromEncodedObject(name, "ASCII", "strict");
                    if (new_name == NULL) {
                        return NULL;
                    }
                }

                // 将新的字段名对象添加到self->names元组中
                PyTuple_SET_ITEM(self->names, i, new_name);
                // 将字段名和字段值添加到self->fields字典中
                if (PyDict_SetItem(self->fields, new_name, field) != 0) {
                    return NULL;
                }
            }
        }
    }

    // 如果数组类型是扩展类型,设置元素大小和对齐方式
    if (PyTypeNum_ISEXTENDED(self->type_num)) {
        self->elsize = elsize;
        self->alignment = alignment;
    }

    /*
     * 我们使用转换为字符的整数以保持与pickle数组的向后兼容性。
     * 以前的版本使用int编码标志,即使在PyArray_Descr结构中实际上是一个char。
     */
    if (int_dtypeflags < 0 && int_dtypeflags >= -128) {
        /* NumPy以前使用的是char类型。所以如果是有符号数,进行规范化。 */
        int_dtypeflags += 128;
    }
    // 将整数标志转换为dtypeflags
    dtypeflags = int_dtypeflags;
    # 如果 dtypeflags 不等于 int_dtypeflags,抛出值错误异常,并返回空值
    if (dtypeflags != int_dtypeflags) {
        PyErr_Format(PyExc_ValueError,
                     "incorrect value for flags variable (overflow)");
        return NULL;
    }
    else {
        # 将 self 对象的 flags 属性设置为 dtypeflags
        self->flags = dtypeflags;
    }

    # 如果 version 小于 3,调用 _descr_find_object 函数来设置 self 对象的 flags 属性
    if (version < 3) {
        self->flags = _descr_find_object((PyArray_Descr *)self);
    }

    """
     * 我们对 metadata 持有引用,所以在丢弃 Py_None 时不需要更改引用计数。
     """
    # 如果 metadata 是 Py_None,则将其设置为 NULL
    if (metadata == Py_None) {
        metadata = NULL;
    }

    # 如果 self 对象是日期时间类型,并且 metadata 不为 NULL
    if (PyDataType_ISDATETIME(self) && (metadata != NULL)) {
        PyObject *old_metadata;
        PyArray_DatetimeMetaData temp_dt_data;

        # 如果 metadata 不是元组或者元组大小不为 2,则抛出值错误异常,并返回空值
        if ((! PyTuple_Check(metadata)) || (PyTuple_Size(metadata) != 2)) {
            PyErr_Format(PyExc_ValueError,
                    "Invalid datetime dtype (metadata, c_metadata): %R",
                    metadata);
            return NULL;
        }

        # 将元组第二个元素转换为日期时间元数据,存储在 temp_dt_data 中
        if (convert_datetime_metadata_tuple_to_datetime_metadata(
                                    PyTuple_GET_ITEM(metadata, 1),
                                    &temp_dt_data,
                                    NPY_TRUE) < 0) {
            return NULL;
        }

        # 保存旧的 metadata 引用,并更新 self 对象的 metadata 和 c_metadata 字段
        old_metadata = self->metadata;
        self->metadata = PyTuple_GET_ITEM(metadata, 0);
        memcpy((char *) &((PyArray_DatetimeDTypeMetaData *)self->c_metadata)->meta,
               (char *) &temp_dt_data,
               sizeof(PyArray_DatetimeMetaData));
        Py_XINCREF(self->metadata);
        Py_XDECREF(old_metadata);
    }
    else {
        # 否则,保存旧的 metadata 引用,并更新 self 对象的 metadata 字段
        PyObject *old_metadata = self->metadata;
        self->metadata = metadata;
        Py_XINCREF(self->metadata);
        Py_XDECREF(old_metadata);
    }

    # 返回 Py_None
    Py_RETURN_NONE;
/*NUMPY_API
 *
 * Get type-descriptor from an object forcing alignment if possible
 * None goes to DEFAULT type.
 *
 * any object with the .fields attribute and/or .itemsize attribute (if the
 *.fields attribute does not give the total size -- i.e. a partial record
 * naming).  If itemsize is given it must be >= size computed from fields
 *
 * The .fields attribute must return a convertible dictionary if present.
 * Result inherits from NPY_VOID.
*/
NPY_NO_EXPORT int
PyArray_DescrAlignConverter(PyObject *obj, PyArray_Descr **at)
{
    // 调用_convert_from_any函数,尝试从obj转换为PyArray_Descr,并强制对齐
    *at = _convert_from_any(obj, 1);
    // 返回转换是否成功的标志
    return (*at) ? NPY_SUCCEED : NPY_FAIL;
}

/*NUMPY_API
 *
 * Get type-descriptor from an object forcing alignment if possible
 * None goes to NULL.
 */
NPY_NO_EXPORT int
PyArray_DescrAlignConverter2(PyObject *obj, PyArray_Descr **at)
{
    // 如果obj为Py_None,则将*at设置为NULL
    if (obj == Py_None) {
        *at = NULL;
        // 返回成功标志
        return NPY_SUCCEED;
    }
    else {
        // 否则调用PyArray_DescrAlignConverter进行转换
        return PyArray_DescrAlignConverter(obj, at);
    }
}



/*NUMPY_API
 *
 * returns a copy of the PyArray_Descr structure with the byteorder
 * altered:
 * no arguments:  The byteorder is swapped (in all subfields as well)
 * single argument:  The byteorder is forced to the given state
 * (in all subfields as well)
 *
 * Valid states:  ('big', '>') or ('little' or '<')
 * ('native', or '=')
 *
 * If a descr structure with | is encountered it's own
 * byte-order is not changed but any fields are:
 *
 *
 * Deep bytorder change of a data-type descriptor
 * *** Leaves reference count of self unchanged --- does not DECREF self ***
 */
NPY_NO_EXPORT PyArray_Descr *
PyArray_DescrNewByteorder(PyArray_Descr *oself, char newendian)
{
    char endian;

    // 如果oself不是旧式的dtype,则返回TypeError
    if (!PyDataType_ISLEGACY(oself)) {
        PyErr_SetString(PyExc_TypeError,
            "Cannot use DescrNewByteOrder for this new style DTypes.");
        return NULL;
    }

    // 将oself转换为旧式的dtype结构体
    _PyArray_LegacyDescr *self = (_PyArray_LegacyDescr *)oself;
    // 创建一个oself的拷贝new
    _PyArray_LegacyDescr *new = (_PyArray_LegacyDescr *)PyArray_DescrNew(oself);
    if (new == NULL) {
        return NULL;
    }
    // 获取new的字节顺序
    endian = new->byteorder;
    // 如果endian不是NPY_IGNORE
    if (endian != NPY_IGNORE) {
        // 如果newendian为NPY_SWAP,则交换字节顺序
        if (newendian == NPY_SWAP) {
            /* swap byteorder */
            // 如果当前字节顺序是大端序,则设为反向的小端序,反之亦然
            if (PyArray_ISNBO(endian)) {
                endian = NPY_OPPBYTE;
            }
            else {
                endian = NPY_NATBYTE;
            }
            new->byteorder = endian;
        }
        // 如果newendian不是NPY_IGNORE,则设定新的字节顺序
        else if (newendian != NPY_IGNORE) {
            new->byteorder = newendian;
        }
    }
    // 检查是否有字段描述信息存在
    if (PyDataType_HASFIELDS(new)) {
        PyObject *newfields;    // 新字段的字典对象
        PyObject *key, *value;  // 键和值对象
        PyObject *newvalue;     // 新值对象
        PyObject *old;          // 旧值对象
        PyArray_Descr *newdescr; // 新的数组描述符对象
        Py_ssize_t pos = 0;     // 迭代器位置
        int len, i;             // 长度和迭代器变量

        // 创建一个新的空字典对象来存储新字段
        newfields = PyDict_New();
        if (newfields == NULL) {
            Py_DECREF(new);
            return NULL;
        }
        /* 创建具有替换 PyArray_Descr 对象的新字典 */
        // 遍历原字段字典
        while (PyDict_Next(self->fields, &pos, &key, &value)) {
            // 跳过标题键
            if (NPY_TITLE_KEY(key, value)) {
                continue;
            }
            // 检查键是否为 Unicode 对象,值是否为元组对象且长度至少为2
            if (!PyUnicode_Check(key) || !PyTuple_Check(value) ||
                ((len=PyTuple_GET_SIZE(value)) < 2)) {
                continue;
            }
            // 获取原字段元组中的第一个元素,即旧的数组描述符对象
            old = PyTuple_GET_ITEM(value, 0);
            // 如果旧值不是数组描述符对象,则跳过
            if (!PyArray_DescrCheck(old)) {
                continue;
            }
            // 使用新的字节顺序创建一个新的数组描述符对象
            newdescr = PyArray_DescrNewByteorder(
                    (PyArray_Descr *)old, newendian);
            // 如果创建失败,释放资源并返回空
            if (newdescr == NULL) {
                Py_DECREF(newfields); Py_DECREF(new);
                return NULL;
            }
            // 创建一个新的元组对象,将新的数组描述符对象放在第一个位置
            newvalue = PyTuple_New(len);
            PyTuple_SET_ITEM(newvalue, 0, (PyObject *)newdescr);
            // 将原元组对象中的其余元素复制到新元组对象中
            for (i = 1; i < len; i++) {
                old = PyTuple_GET_ITEM(value, i);
                Py_INCREF(old);
                PyTuple_SET_ITEM(newvalue, i, old);
            }
            // 将新值元组对象添加到新字段字典中
            int ret = PyDict_SetItem(newfields, key, newvalue);
            Py_DECREF(newvalue);
            // 如果添加失败,释放资源并返回空
            if (ret < 0) {
                Py_DECREF(newfields);
                Py_DECREF(new);
                return NULL;
            }
        }
        // 释放原字段字典对象,并将新字段字典对象赋给新对象的字段
        Py_DECREF(new->fields);
        new->fields = newfields;
    }
    // 如果存在子数组对象
    if (new->subarray) {
        // 释放原子数组对象的基础描述符对象,并使用新的字节顺序创建一个新的描述符对象
        Py_DECREF(new->subarray->base);
        new->subarray->base = PyArray_DescrNewByteorder(
                self->subarray->base, newendian);
        // 如果创建失败,释放资源并返回空
        if (new->subarray->base == NULL) {
            Py_DECREF(new);
            return NULL;
        }
    }
    // 返回新的数组描述符对象
    return (PyArray_Descr *)new;
/*
 * 创建一个新的字节顺序的数组描述符对象。
 * 这个函数用于处理数组描述符的字节顺序。
 * 如果没有指定字节顺序,则默认为 NPY_SWAP。
 */
static PyObject *
arraydescr_newbyteorder(PyArray_Descr *self, PyObject *args)
{
    // 默认的字节顺序为 NPY_SWAP
    char endian = NPY_SWAP;

    // 尝试解析传入的参数,如果解析失败则返回 NULL
    if (!PyArg_ParseTuple(args, "|O&:newbyteorder", PyArray_ByteorderConverter,
                &endian)) {
        return NULL;
    }

    // 调用 PyArray_DescrNewByteorder 函数来创建新的字节顺序的数组描述符对象
    return (PyObject *)PyArray_DescrNewByteorder(self, endian);
}

/*
 * 获取数组描述符类中的特定项。
 * 当传入的参数个数不为 1 时,返回一个 TypeError 异常。
 * 否则,调用 Py_GenericAlias 函数处理参数并返回结果。
 */
static PyObject *
arraydescr_class_getitem(PyObject *cls, PyObject *args)
{
    // 检查传入参数的长度
    const Py_ssize_t args_len = PyTuple_Check(args) ? PyTuple_Size(args) : 1;

    // 如果参数个数不为 1,则返回一个带有错误信息的 TypeError 异常
    if (args_len != 1) {
        return PyErr_Format(PyExc_TypeError,
                            "Too %s arguments for %s",
                            args_len > 1 ? "many" : "few",
                            ((PyTypeObject *)cls)->tp_name);
    }

    // 调用 Py_GenericAlias 函数处理参数并返回结果
    return Py_GenericAlias(cls, args);
}

/*
 * 数组描述符对象的方法定义数组。
 * 包括用于 pickling 的方法、newbyteorder 方法以及用于 typing 的 __class_getitem__ 方法。
 */
static PyMethodDef arraydescr_methods[] = {
    /* for pickling */
    {"__reduce__",
        (PyCFunction)arraydescr_reduce,
        METH_VARARGS, NULL},
    {"__setstate__",
        (PyCFunction)arraydescr_setstate,
        METH_VARARGS, NULL},
    {"newbyteorder",
        (PyCFunction)arraydescr_newbyteorder,
        METH_VARARGS, NULL},
    /* for typing; requires python >= 3.9 */
    {"__class_getitem__",
        (PyCFunction)arraydescr_class_getitem,
        METH_CLASS | METH_O, NULL},
    {NULL, NULL, 0, NULL}           /* sentinel */
};

/*
 * 检查结构化数据类型 'dtype' 是否具有简单的未对齐布局。
 * 当所有字段按顺序排列且没有对齐填充时返回 true。
 * 如果满足条件,可以通过字段名和数据类型的列表重新构建 dtype,而不需要额外的 dtype 参数。
 * 返回 1 表示具有简单的布局,返回 0 表示不是。
 */
NPY_NO_EXPORT int
is_dtype_struct_simple_unaligned_layout(PyArray_Descr *dtype)
{
    PyObject *names, *fields, *key, *tup, *title;
    Py_ssize_t i, names_size;
    PyArray_Descr *fld_dtype;
    int fld_offset;
    npy_intp total_offset;

    /* 从 dtype 中获取一些属性 */
    names = PyDataType_NAMES(dtype);
    names_size = PyTuple_GET_SIZE(names);
    fields = PyDataType_FIELDS(dtype);

    /* 从零开始计算总偏移量 */
    total_offset = 0;

    for (i = 0; i < names_size; ++i) {
        key = PyTuple_GET_ITEM(names, i);
        if (key == NULL) {
            return 0;
        }
        tup = PyDict_GetItem(fields, key);
        if (tup == NULL) {
            return 0;
        }
        if (!PyArg_ParseTuple(tup, "Oi|O", &fld_dtype, &fld_offset, &title)) {
            PyErr_Clear();
            return 0;
        }
        /* 如果这个字段不按照预期顺序排列,不是简单的布局 */
        if (total_offset != fld_offset) {
            return 0;
        }
        /* 获取下一个偏移量 */
        total_offset += fld_dtype->elsize;
    }

    /*
     * 如果 itemsize 不等于最终偏移量,不是简单的布局。
     */
    if (total_offset != dtype->elsize) {
        return 0;
    }

    /* 所有测试通过,具有简单的布局 */
    return 1;
}
    # 返回整数值 1
    return 1;
}

/*
 * The general dtype repr function.
 */
static PyObject *
arraydescr_repr(PyArray_Descr *dtype)
{
    PyObject *_numpy_dtype;
    PyObject *res;
    // 导入 numpy._core._dtype 模块
    _numpy_dtype = PyImport_ImportModule("numpy._core._dtype");
    if (_numpy_dtype == NULL) {
        return NULL;
    }
    // 调用 _numpy_dtype 模块的 __repr__ 方法,返回 dtype 的字符串表示
    res = PyObject_CallMethod(_numpy_dtype, "__repr__", "O", dtype);
    Py_DECREF(_numpy_dtype);
    return res;
}
/*
 * The general dtype str function.
 */
static PyObject *
arraydescr_str(PyArray_Descr *dtype)
{
    PyObject *_numpy_dtype;
    PyObject *res;
    // 导入 numpy._core._dtype 模块
    _numpy_dtype = PyImport_ImportModule("numpy._core._dtype");
    if (_numpy_dtype == NULL) {
        return NULL;
    }
    // 调用 _numpy_dtype 模块的 __str__ 方法,返回 dtype 的字符串表示
    res = PyObject_CallMethod(_numpy_dtype, "__str__", "O", dtype);
    Py_DECREF(_numpy_dtype);
    return res;
}

static PyObject *
arraydescr_richcompare(PyArray_Descr *self, PyObject *other, int cmp_op)
{
    // 将 other 转换为 PyArray_Descr 类型
    PyArray_Descr *new = _convert_from_any(other, 0);
    if (new == NULL) {
        /* Cannot convert `other` to dtype */
        PyErr_Clear();
        // 返回未实现的 NotImplemented
        Py_RETURN_NOTIMPLEMENTED;
    }

    npy_bool ret;
    switch (cmp_op) {
    case Py_LT:
        // 比较 self 和 new 是否等价,并且 self 可以转换为 new
        ret = !PyArray_EquivTypes(self, new) && PyArray_CanCastTo(self, new);
        Py_DECREF(new);
        return PyBool_FromLong(ret);
    case Py_LE:
        // 检查 self 是否可以转换为 new
        ret = PyArray_CanCastTo(self, new);
        Py_DECREF(new);
        return PyBool_FromLong(ret);
    case Py_EQ:
        // 检查 self 和 new 是否等价
        ret = PyArray_EquivTypes(self, new);
        Py_DECREF(new);
        return PyBool_FromLong(ret);
    case Py_NE:
        // 检查 self 和 new 是否不等价
        ret = !PyArray_EquivTypes(self, new);
        Py_DECREF(new);
        return PyBool_FromLong(ret);
    case Py_GT:
        // 比较 self 和 new 是否不等价,并且 new 可以转换为 self
        ret = !PyArray_EquivTypes(self, new) && PyArray_CanCastTo(new, self);
        Py_DECREF(new);
        return PyBool_FromLong(ret);
    case Py_GE:
        // 检查 new 是否可以转换为 self
        ret = PyArray_CanCastTo(new, self);
        Py_DECREF(new);
        return PyBool_FromLong(ret);
    default:
        Py_DECREF(new);
        // 返回未实现的 NotImplemented
        Py_RETURN_NOTIMPLEMENTED;
    }
}

static int
descr_nonzero(PyObject *NPY_UNUSED(self))
{
    /* `bool(np.dtype(...)) == True` for all dtypes. Needed to override default
     * nonzero implementation, which checks if `len(object) > 0`. */
    // 所有的 dtype 的 bool() 操作都返回 True,用于覆盖默认的非零判断实现
    return 1;
}

static PyNumberMethods descr_as_number = {
    .nb_bool = (inquiry)descr_nonzero,
};

/*************************************************************************
 ****************   Implement Mapping Protocol ***************************
 *************************************************************************/

static Py_ssize_t
descr_length(PyObject *self0)
{
    PyArray_Descr *self = (PyArray_Descr *)self0;

    if (PyDataType_HASFIELDS(self)) {
        // 如果 self 具有字段信息,返回字段数目
        return PyTuple_GET_SIZE(PyDataType_NAMES(self));
    }
    else {
        // 如果 self 没有字段信息,返回 0
        return 0;
    }
}

static PyObject *
descr_repeat(PyObject *self, Py_ssize_t length)
{
    PyObject *tup;
    PyArray_Descr *new;
    // 代码继续...
    # 检查长度是否小于 0
    if (length < 0) {
        # 如果小于 0,则返回一个相应的异常,并包含错误信息和长度值
        return PyErr_Format(PyExc_ValueError,
                "Array length must be >= 0, not %"NPY_INTP_FMT, (npy_intp)length);
    }
    # 使用给定的 self 和 length 构建一个 Python 元组对象
    tup = Py_BuildValue("O" NPY_SSIZE_T_PYFMT, self, length);
    # 检查元组对象是否构建成功
    if (tup == NULL) {
        # 如果构建失败,则返回 NULL
        return NULL;
    }
    # 将构建的元组对象转换为适当的数据结构 new
    new = _convert_from_any(tup, 0);
    # 释放元组对象的引用计数
    Py_DECREF(tup);
    # 返回转换后的新对象
    return (PyObject *)new;
static int
_check_has_fields(PyArray_Descr *self)
{
    // 检查给定的 NumPy 数据类型描述符是否具有字段信息
    if (!PyDataType_HASFIELDS(self)) {
        // 若没有字段信息,则抛出一个 Key 错误异常
        PyErr_Format(PyExc_KeyError, "There are no fields in dtype %S.", self);
        return -1;
    }
    else {
        // 如果有字段信息,则返回 0 表示成功
        return 0;
    }
}

static PyObject *
_subscript_by_name(_PyArray_LegacyDescr *self, PyObject *op)
{
    // 根据字段名从字段字典中获取对应的对象
    PyObject *obj = PyDict_GetItemWithError(self->fields, op);
    if (obj == NULL) {
        // 如果获取失败,且没有设置过错误状态,则抛出 Key 错误异常
        if (!PyErr_Occurred()) {
            PyErr_Format(PyExc_KeyError,
                    "Field named %R not found.", op);
        }
        return NULL;
    }
    // 从获取到的对象中取出描述符对象
    PyObject *descr = PyTuple_GET_ITEM(obj, 0);
    // 增加描述符的引用计数并返回
    Py_INCREF(descr);
    return descr;
}

static PyObject *
_subscript_by_index(_PyArray_LegacyDescr *self, Py_ssize_t i)
{
    // 根据索引从字段名元组中获取字段名对象
    PyObject *name = PySequence_GetItem(self->names, i);
    PyObject *ret;
    if (name == NULL) {
        // 如果获取失败,则抛出索引错误异常
        PyErr_Format(PyExc_IndexError,
                     "Field index %zd out of range.", i);
        return NULL;
    }
    // 根据字段名对象调用 _subscript_by_name 获取对应的描述符对象
    ret = _subscript_by_name(self, name);
    // 减少字段名对象的引用计数
    Py_DECREF(name);
    return ret;
}

static npy_bool
_is_list_of_strings(PyObject *obj)
{
    int seqlen, i;
    // 检查对象是否为列表类型
    if (!PyList_CheckExact(obj)) {
        return NPY_FALSE;
    }
    // 获取列表的长度
    seqlen = PyList_GET_SIZE(obj);
    // 遍历列表中的每个元素,检查是否都是 Unicode 字符串类型
    for (i = 0; i < seqlen; i++) {
        PyObject *item = PyList_GET_ITEM(obj, i);
        if (!PyUnicode_Check(item)) {
            return NPY_FALSE;
        }
    }

    return NPY_TRUE;
}

NPY_NO_EXPORT PyArray_Descr *
arraydescr_field_subset_view(_PyArray_LegacyDescr *self, PyObject *ind)
{
    int seqlen, i;
    PyObject *fields = NULL;
    PyObject *names = NULL;

    // 获取索引对象的长度
    seqlen = PySequence_Size(ind);
    if (seqlen == -1) {
        return NULL;
    }

    // 创建一个新的空字典对象用于存储字段
    fields = PyDict_New();
    if (fields == NULL) {
        goto fail;
    }
    // 创建一个新的元组对象来存储字段名
    names = PyTuple_New(seqlen);
    if (names == NULL) {
        goto fail;
    }
    // 遍历输入的序列,处理每个元素
    for (i = 0; i < seqlen; i++) {
        PyObject *name;
        PyObject *tup;

        // 获取序列中第i个元素作为字段名
        name = PySequence_GetItem(ind, i);
        if (name == NULL) {
            // 如果获取字段名失败,跳转到错误处理标签fail
            goto fail;
        }

        /* 让字段名元组现在就获取一个引用,这样如果后面发生错误,我们就不需要
         * 在释放引用之前再次递减它。
         */
        PyTuple_SET_ITEM(names, i, name);

        // 在self->fields字典中查找字段名对应的元组tup
        tup = PyDict_GetItemWithError(self->fields, name);
        if (tup == NULL) {
            // 如果字段名在self->fields中不存在,设置KeyError异常
            if (!PyErr_Occurred()) {
                PyErr_SetObject(PyExc_KeyError, name);
            }
            // 跳转到错误处理标签fail
            goto fail;
        }

        /* 禁止使用标题作为索引 */
        if (PyTuple_Size(tup) == 3) {
            // 如果元组tup的大小为3,表示有标题,获取标题对象
            PyObject *title = PyTuple_GET_ITEM(tup, 2);
            // 比较标题和字段名是否相等
            int titlecmp = PyObject_RichCompareBool(title, name, Py_EQ);
            if (titlecmp < 0) {
                // 比较出错,跳转到错误处理标签fail
                goto fail;
            }
            if (titlecmp == 1) {
                /* 如果标题 == 字段名,说明传入的是标题而不是字段名 */
                PyErr_SetString(PyExc_KeyError,
                            "cannot use field titles in multi-field index");
                // 跳转到错误处理标签fail
                goto fail;
            }
            // 将标题和元组tup添加到fields字典中
            if (PyDict_SetItem(fields, title, tup) < 0) {
                // 添加失败,跳转到错误处理标签fail
                goto fail;
            }
        }
        /* 禁止重复的字段索引 */
        if (PyDict_Contains(fields, name)) {
            // 如果fields字典中已经包含字段名name
            PyObject *msg = NULL;
            PyObject *fmt = PyUnicode_FromString(
                                   "duplicate field of name {!r}");
            if (fmt != NULL) {
                // 格式化错误消息
                msg = PyObject_CallMethod(fmt, "format", "O", name);
                Py_DECREF(fmt);
            }
            // 设置ValueError异常,并传入错误消息
            PyErr_SetObject(PyExc_ValueError, msg);
            Py_XDECREF(msg);
            // 跳转到错误处理标签fail
            goto fail;
        }
        // 将字段名name和元组tup添加到fields字典中
        if (PyDict_SetItem(fields, name, tup) < 0) {
            // 添加失败,跳转到错误处理标签fail
            goto fail;
        }
    }

    // 创建一个新的数组描述符view_dtype,类型为NPY_VOID
    _PyArray_LegacyDescr *view_dtype = (_PyArray_LegacyDescr *)PyArray_DescrNewFromType(NPY_VOID);
    if (view_dtype == NULL) {
        // 如果创建失败,跳转到错误处理标签fail
        goto fail;
    }
    // 设置view_dtype的元素大小、字段名元组、字段字典和标志
    view_dtype->elsize = self->elsize;
    view_dtype->names = names;
    view_dtype->fields = fields;
    view_dtype->flags = self->flags;
    // 返回创建的数组描述符view_dtype
    return (PyArray_Descr *)view_dtype;
fail:
    Py_XDECREF(fields);  # 释放 fields 对象的引用计数
    Py_XDECREF(names);   # 释放 names 对象的引用计数
    return NULL;         # 返回 NULL 表示函数执行失败
}

static PyObject *
descr_subscript(PyArray_Descr *self, PyObject *op)
{
    _PyArray_LegacyDescr *lself = (_PyArray_LegacyDescr *)self;  # 将 self 转换为 _PyArray_LegacyDescr 类型

    if (_check_has_fields(self) < 0) {  # 检查 self 是否有字段,小于 0 表示出错
        return NULL;  # 返回 NULL 表示出错
    }

    if (PyUnicode_Check(op)) {  # 检查 op 是否为 Unicode 对象
        return _subscript_by_name(lself, op);  # 根据字段名 op 返回对应的子描述符
    }
    else if (_is_list_of_strings(op)) {  # 检查 op 是否为字符串列表
        return (PyObject *)arraydescr_field_subset_view(lself, op);  # 返回字段子集的视图
    }
    else {
        Py_ssize_t i = PyArray_PyIntAsIntp(op);  # 将 op 转换为 Py_ssize_t 类型
        if (error_converting(i)) {  # 检查是否在转换过程中出错
            /* 如果转换为整数出现类型错误,调整错误消息 */
            PyObject *err = PyErr_Occurred();  # 获取当前的错误对象
            if (PyErr_GivenExceptionMatches(err, PyExc_TypeError)) {  # 检查错误类型是否为 TypeError
                PyErr_SetString(PyExc_TypeError,
                        "Field key must be an integer field offset, "
                        "single field name, or list of field names.");  # 设置错误消息
            }
            return NULL;  # 返回 NULL 表示出错
        }
        return _subscript_by_index(lself, i);  # 根据索引 i 返回对应的子描述符
    }
}

static PySequenceMethods descr_as_sequence = {
    (lenfunc) descr_length,                  /* sq_length */  # 返回序列长度的函数指针
    (binaryfunc) NULL,                       /* sq_concat */  # 序列连接函数指针,未实现
    (ssizeargfunc) descr_repeat,             /* sq_repeat */  # 序列重复函数指针
    (ssizeargfunc) NULL,                     /* sq_item */  # 获取序列项的函数指针,未实现
    (ssizessizeargfunc) NULL,                /* sq_slice */  # 获取序列切片的函数指针,未实现
    (ssizeobjargproc) NULL,                  /* sq_ass_item */  # 设置序列项的函数指针,未实现
    (ssizessizeobjargproc) NULL,             /* sq_ass_slice */  # 设置序列切片的函数指针,未实现
    (objobjproc) NULL,                       /* sq_contains */  # 序列包含检查的函数指针,未实现
    (binaryfunc) NULL,                       /* sq_inplace_concat */  # 序列原地连接的函数指针,未实现
    (ssizeargfunc) NULL,                     /* sq_inplace_repeat */  # 序列原地重复的函数指针,未实现
};

static PyMappingMethods descr_as_mapping = {
    descr_length,                                /* mp_length*/  # 映射长度函数指针
    (binaryfunc)descr_subscript,                 /* mp_subscript*/  # 映射子脚本函数指针
    (objobjargproc)NULL,                         /* mp_ass_subscript*/  # 映射赋值子脚本函数指针,未实现
};

/****************** End of Mapping Protocol ******************************/

/*
 * NOTE: Since this is a MetaClass, the name has Full appended here, the
 *       correct name of the type is PyArrayDescr_Type.
 */
NPY_NO_EXPORT PyArray_DTypeMeta PyArrayDescr_TypeFull = {
    {{
        /* NULL represents `type`, this is set to DTypeMeta at import time */
        // 使用 NULL 表示 `type`,在导入时设置为 DTypeMeta
        PyVarObject_HEAD_INIT(NULL, 0)
        // 初始化 Python 变量对象头部,指定初始值为 NULL 和大小为 0

        .tp_name = "numpy.dtype",
        // 设置类型对象的名称为 "numpy.dtype"
        
        .tp_basicsize = sizeof(PyArray_Descr),
        // 设置类型对象的基本大小为 PyArray_Descr 结构体的大小
        
        .tp_dealloc = (destructor)arraydescr_dealloc,
        // 设置类型对象的析构函数为 arraydescr_dealloc
        
        .tp_repr = (reprfunc)arraydescr_repr,
        // 设置类型对象的表示函数为 arraydescr_repr
        
        .tp_as_number = &descr_as_number,
        // 设置类型对象的数字操作结构体指针为 descr_as_number
        
        .tp_as_sequence = &descr_as_sequence,
        // 设置类型对象的序列操作结构体指针为 descr_as_sequence
        
        .tp_as_mapping = &descr_as_mapping,
        // 设置类型对象的映射操作结构体指针为 descr_as_mapping
        
        .tp_str = (reprfunc)arraydescr_str,
        // 设置类型对象的字符串表示函数为 arraydescr_str
        
        .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
        // 设置类型对象的标志为默认标志和基类型标志的按位或
        
        .tp_richcompare = (richcmpfunc)arraydescr_richcompare,
        // 设置类型对象的富比较函数为 arraydescr_richcompare
        
        .tp_methods = arraydescr_methods,
        // 设置类型对象的方法列表为 arraydescr_methods
        
        .tp_members = arraydescr_members,
        // 设置类型对象的成员列表为 arraydescr_members
        
        .tp_getset = arraydescr_getsets,
        // 设置类型对象的属性获取设置函数列表为 arraydescr_getsets
        
        .tp_new = arraydescr_new,
        // 设置类型对象的新建函数为 arraydescr_new
    },},
    // 结束 PyVarObject_HEAD_INIT 初始化

    .singleton = NULL,
    // 设置 singleton 属性为 NULL

    .type_num = -1,
    // 设置 type_num 属性为 -1,表示未指定具体的类型编号

    .scalar_type = NULL,
    // 设置 scalar_type 属性为 NULL,表示未指定具体的标量类型

    .flags = NPY_DT_ABSTRACT,
    // 设置 flags 属性为 NPY_DT_ABSTRACT,表示这是一个抽象数据类型
};



# 结束了一个代码块,该代码块可能是一个函数、循环、条件语句或其他代码结构的结束