NumPy 源码解析(七十)
.\numpy\numpy\_core\src\multiarray\nditer_impl.h
/*
* This is a PRIVATE INTERNAL NumPy header, intended to be used *ONLY*
* by the iterator implementation code. All other internal NumPy code
* should use the exposed iterator API.
*/
/********** ITERATOR CONSTRUCTION TIMING **************/
unsigned int hi, lo; \
__asm__ __volatile__ ( \
"rdtsc" \
: "=d" (hi), "=a" (lo)); \
var = (((unsigned long long)hi) << 32) | lo; \
}
printf("%30s: start\n",
c_temp = var; \
}
printf("%30s: %6.0f clocks\n",
((double)(var-c_temp))); \
c_temp = var; \
}
/******************************************************/
/********** PRINTF DEBUG TRACING **************/
/**********************************************/
/* Rounds up a number of bytes to be divisible by sizeof intptr_t */
/* Internal iterator flags */
/* The perm is the identity */
/* The perm has negative entries (indicating flipped axes) */
/* The iterator is tracking an index */
/* The iterator is tracking a multi-index */
/* The iteration order was forced on construction */
/* The inner loop is handled outside the iterator */
/* The iterator is ranged */
/* The iterator is buffered */
/* The iterator should grow the buffered inner loop when possible */
/* 定义一个位掩码,用于表示迭代器需要的各种特性 */
/* 仅有一个迭代,可以为其特化iternext */
/* 延迟缓冲区分配,直到第一次调用Reset* */
/* 迭代过程中需要 API 访问 */
/* 迭代包括一个或多个操作数的缩减 */
/* 缩减迭代下次不需要重新计算缩减循环 */
/*
* 用于所有传输函数的(组合)ArrayMethod标志的偏移量。
* 目前,我们使用最高8位。
*/
/* 内部迭代器每操作数的迭代器标志 */
/* 操作数将被写入 */
/* 操作数将被读取 */
/* 需要类型转换/字节交换/对齐 */
/* 操作数从不需要缓冲 */
/* 操作数已对齐 */
/* 操作数正在被缩减 */
/* 操作数用于临时使用,没有后备数组 */
/* 复制缓冲区到数组时需要掩码 */
/* 操作数的数据指针指向其缓冲区 */
/* 必须复制操作数(如果还有ITFLAG_WRITE,则使用UPDATEIFCOPY) */
/* 操作数具有临时数据,在dealloc时写回 */
/*
* 迭代器的数据布局由三元组(itflags, ndim, nop)完全指定。
* 这三个变量预期在调用这些宏的所有函数中存在,
* 要么作为从迭代器初始化的真实变量,要么作为专门函数(如各种iternext函数)中的常量。
*/
struct NpyIter_InternalOnly {
/* 初始固定位置数据 */
npy_uint32 itflags;
npy_uint8 ndim, nop;
npy_int8 maskop;
npy_intp itersize, iterstart, iterend;
/* 只有在设置了RANGED或BUFFERED时才使用iterindex */
npy_intp iterindex;
/* 剩余的是变量数据 */
char iter_flexdata[];
};
typedef struct NpyIter_AxisData_tag NpyIter_AxisData;
typedef struct NpyIter_TransferInfo_tag NpyIter_TransferInfo;
typedef struct NpyIter_BufferData_tag NpyIter_BufferData;
typedef npy_int16 npyiter_opitflags;
/* 迭代器成员的字节大小 */
NPY_PTR_ALIGNED(NPY_MAXDIMS)
((NPY_SIZEOF_PY_INTPTR_T)*(nop))
/* 计算并返回重置数据指针所需的字节数,考虑指针的数量和大小 */
((NPY_SIZEOF_PY_INTPTR_T)*(nop+1))
/* 计算并返回基础偏移量所需的字节数,考虑指针的数量和大小 */
((NPY_SIZEOF_PY_INTPTR_T)*(nop+1)) /* 可能是 intp 的大小 */
/* 计算并返回操作数数组所需的字节数,考虑指针的数量和大小 */
((NPY_SIZEOF_PY_INTPTR_T)*(nop))
/* 计算并返回操作标志数组所需的字节数,确保对齐到指针的大小 */
(NPY_PTR_ALIGNED(sizeof(npyiter_opitflags) * nop))
/* 计算并返回缓冲区数据结构所需的字节数,考虑缓冲区标志位和相关指针数量 */
((itflags&NPY_ITFLAG_BUFFER) ? ( \
(NPY_SIZEOF_PY_INTPTR_T)*(6 + 5*nop) + sizeof(NpyIter_TransferInfo) * nop) : 0)
/* 从迭代器的灵活数据开始计算,返回排列数据的字节偏移量 */
(0)
/* 计算并返回数据类型数组的字节偏移量,考虑迭代器标志、维度和操作数指针的数量 */
(NIT_PERM_OFFSET() + \
NIT_PERM_SIZEOF(itflags, ndim, nop))
/* 计算并返回重置数据指针的字节偏移量,考虑迭代器标志、维度和操作数指针的数量 */
(NIT_DTYPES_OFFSET(itflags, ndim, nop) + \
NIT_DTYPES_SIZEOF(itflags, ndim, nop))
/* 计算并返回基础偏移量的字节偏移量,考虑迭代器标志、维度和操作数指针的数量 */
(NIT_RESETDATAPTR_OFFSET(itflags, ndim, nop) + \
NIT_RESETDATAPTR_SIZEOF(itflags, ndim, nop))
/* 计算并返回操作数数组的字节偏移量,考虑迭代器标志、维度和操作数指针的数量 */
(NIT_BASEOFFSETS_OFFSET(itflags, ndim, nop) + \
NIT_BASEOFFSETS_SIZEOF(itflags, ndim, nop))
/* 计算并返回操作标志数组的字节偏移量,确保对齐到指针的大小,考虑迭代器标志、维度和操作数指针的数量 */
(NIT_OPERANDS_OFFSET(itflags, ndim, nop) + \
NIT_OPERANDS_SIZEOF(itflags, ndim, nop))
/* 计算并返回缓冲区数据结构的字节偏移量,考虑迭代器标志、维度和操作数指针的数量 */
(NIT_OPITFLAGS_OFFSET(itflags, ndim, nop) + \
NIT_OPITFLAGS_SIZEOF(itflags, ndim, nop))
/* 计算并返回轴数据结构的字节偏移量,考虑迭代器标志、维度和操作数指针的数量 */
(NIT_BUFFERDATA_OFFSET(itflags, ndim, nop) + \
NIT_BUFFERDATA_SIZEOF(itflags, ndim, nop))
/* 返回迭代器中 itflags 成员的值 */
((iter)->itflags)
/* 返回迭代器中 ndim 成员的值 */
((iter)->ndim)
/* 返回迭代器中 nop 成员的值 */
((iter)->nop)
/* 返回迭代器中 maskop 成员的值 */
((iter)->maskop)
/* 返回迭代器中 itersize 成员的值 */
(iter->itersize)
/* 返回迭代器中 iterstart 成员的值 */
(iter->iterstart)
/* 返回迭代器中 iterend 成员的值 */
(iter->iterend)
/* 返回迭代器中 iterindex 成员的值 */
(iter->iterindex)
/* 返回迭代器中排列数据的指针 */
iter->iter_flexdata + NIT_PERM_OFFSET()))
/* 返回迭代器中数据类型数组的指针 */
iter->iter_flexdata + NIT_DTYPES_OFFSET(itflags, ndim, nop)))
/* 返回迭代器中重置数据指针数组的指针 */
iter->iter_flexdata + NIT_RESETDATAPTR_OFFSET(itflags, ndim, nop)))
/* 返回迭代器中基础偏移量数组的指针 */
iter->iter_flexdata + NIT_BASEOFFSETS_OFFSET(itflags, ndim, nop)))
/* 返回迭代器中操作数数组的指针 */
iter->iter_flexdata + NIT_OPERANDS_OFFSET(itflags, ndim, nop)))
/* 返回迭代器中操作标志数组的指针 */
iter->iter_flexdata + NIT_OPITFLAGS_OFFSET(itflags, ndim, nop)))
iter->iter_flexdata + NIT_BUFFERDATA_OFFSET(itflags, ndim, nop)))
iter->iter_flexdata + NIT_AXISDATA_OFFSET(itflags, ndim, nop)))
/* Internal-only BUFFERDATA MEMBER ACCESS */
struct NpyIter_TransferInfo_tag {
NPY_cast_info read;
NPY_cast_info write;
NPY_traverse_info clear;
/* Probably unnecessary, but make sure what follows is intptr aligned: */
Py_intptr_t _unused_ensure_alignment[];
};
struct NpyIter_BufferData_tag {
npy_intp buffersize, size, bufiterend,
reduce_pos, reduce_outersize, reduce_outerdim;
Py_intptr_t bd_flexdata;
};
&(bufferdata)->bd_flexdata + 0)
(&(bufferdata)->bd_flexdata + 1*(nop)))
(&(bufferdata)->bd_flexdata + 2*(nop)))
(&(bufferdata)->bd_flexdata + 3*(nop)))
(&(bufferdata)->bd_flexdata + 4*(nop)))
(&(bufferdata)->bd_flexdata + 5*(nop)))
/* Internal-only AXISDATA MEMBER ACCESS. */
struct NpyIter_AxisData_tag {
npy_intp shape, index;
Py_intptr_t ad_flexdata;
};
&(axisdata)->ad_flexdata + 0)
(&(axisdata)->ad_flexdata + 1*(nop+1)))
((nop) + ((itflags&NPY_ITFLAG_HASINDEX) ? 1 : 0))
/* Size of one AXISDATA struct within the iterator */
/* intp shape */ \
1 + \
/* intp index */ \
1 + \
/* intp stride[nop+1] AND char* ptr[nop+1] */ \
2*((nop)+1) \
)*(size_t)NPY_SIZEOF_PY_INTPTR_T)
/*
* Macro to advance an AXISDATA pointer by a specified count.
* Requires that sizeof_axisdata be previously initialized
* to NIT_AXISDATA_SIZEOF(itflags, ndim, nop).
*/
(((char *)(axisdata)) + (index)*sizeof_axisdata))
axisdata = NIT_INDEX_AXISDATA(axisdata, count)
/* Size of the whole iterator */
/* 定义一个宏,用于计算迭代器的大小,包括内部结构和轴数据大小 */
sizeof(struct NpyIter_InternalOnly) + \
NIT_AXISDATA_OFFSET(itflags, ndim, nop) + \
NIT_AXISDATA_SIZEOF(itflags, ndim, nop)*(ndim ? ndim : 1))
/* 内部辅助函数,在实现文件间共享 */
/**
* 撤销迭代器的轴置换。当操作数的维度少于迭代器时,这可能会返回插入的(广播)维度的负值。
*
* @param axis 要撤销迭代器轴置换的轴。
* @param ndim 如果使用 `op_axes`,则为迭代器的维度,否则为操作数的维度。
* @param perm 迭代器轴置换 NIT_PERM(iter)
* @param axis_flipped 如果这是一个翻转的轴(即以相反顺序迭代),则设置为 true,否则为 false。
* 如果不需要该信息,则可以为 NULL。
* @return 未置换的轴。如果没有 `op_axes`,则是正确的;如果有 `op_axes`,则这是对 `op_axes` 的索引(未置换的迭代器轴)。
*/
static inline int
npyiter_undo_iter_axis_perm(
int axis, int ndim, const npy_int8 *perm, npy_bool *axis_flipped)
{
npy_int8 p = perm[axis];
/* 迭代器以相反顺序处理轴,因此根据 ndim 进行调整 */
npy_bool flipped = p < 0;
if (axis_flipped != NULL) {
*axis_flipped = flipped;
}
if (flipped) {
axis = ndim + p;
}
else {
axis = ndim - p - 1;
}
return axis;
}
/* 下面是一些不导出的函数声明,用于操作 NpyIter 结构 */
NPY_NO_EXPORT void
npyiter_coalesce_axes(NpyIter *iter);
NPY_NO_EXPORT int
npyiter_allocate_buffers(NpyIter *iter, char **errmsg);
NPY_NO_EXPORT void
npyiter_goto_iterindex(NpyIter *iter, npy_intp iterindex);
NPY_NO_EXPORT int
npyiter_copy_from_buffers(NpyIter *iter);
NPY_NO_EXPORT int
npyiter_copy_to_buffers(NpyIter *iter, char **prev_dataptrs);
NPY_NO_EXPORT void
npyiter_clear_buffers(NpyIter *iter);
/*
* 获取传输函数的 ArrayMethod 标志位。
* TODO: 此函数应该是公共的,并且应该从 `nditer_impl.h` 中删除,但这要求首先将 ArrayMethod 标志位公开为公共 API。
*/
NPY_NO_EXPORT int
NpyIter_GetTransferFlags(NpyIter *iter);
.\numpy\numpy\_core\src\multiarray\nditer_pywrap.c
/*
* This file implements the CPython wrapper of NpyIter
*
* Copyright (c) 2010 by Mark Wiebe (mwwiebe@gmail.com)
* The University of British Columbia
*
* See LICENSE.txt for the license.
*/
/* Define to prevent deprecated NumPy API usage */
/* Define to enable multiarray module */
/* Clean PY_SSIZE_T */
/* Function declarations not part of the public NumPy C API */
npy_bool npyiter_has_writeback(NpyIter *iter);
/* Structure definition for the Python object */
typedef struct NewNpyArrayIterObject_tag NewNpyArrayIterObject;
struct NewNpyArrayIterObject_tag {
PyObject_HEAD /* Python object header */
NpyIter *iter; /* NpyIter object for iteration */
char started, finished; /* Flags indicating iteration state */
NewNpyArrayIterObject *nested_child; /* Child iterator for nested iteration */
NpyIter_IterNextFunc *iternext; /* Function pointer for iteration */
NpyIter_GetMultiIndexFunc *get_multi_index; /* Function pointer for multi-index */
char **dataptrs; /* Data pointers */
PyArray_Descr **dtypes; /* Array descriptors */
PyArrayObject **operands; /* Array operands */
npy_intp *innerstrides; /* Inner strides */
npy_intp *innerloopsizeptr; /* Inner loop size pointer */
char readflags[NPY_MAXARGS]; /* Read flags */
char writeflags[NPY_MAXARGS]; /* Write flags */
};
/* Function to cache values from NpyIter into NewNpyArrayIterObject */
static int npyiter_cache_values(NewNpyArrayIterObject *self)
{
NpyIter *iter = self->iter;
/* Retrieve iternext function */
self->iternext = NpyIter_GetIterNext(iter, NULL);
if (self->iternext == NULL) {
return -1;
}
/* Retrieve get_multi_index function if available */
if (NpyIter_HasMultiIndex(iter) && !NpyIter_HasDelayedBufAlloc(iter)) {
self->get_multi_index = NpyIter_GetGetMultiIndex(iter, NULL);
}
else {
self->get_multi_index = NULL;
}
/* Retrieve data pointers, descriptors, and operands */
self->dataptrs = NpyIter_GetDataPtrArray(iter);
self->dtypes = NpyIter_GetDescrArray(iter);
self->operands = NpyIter_GetOperandArray(iter);
/* Retrieve inner strides and inner loop size pointer if external loop exists */
if (NpyIter_HasExternalLoop(iter)) {
self->innerstrides = NpyIter_GetInnerStrideArray(iter);
self->innerloopsizeptr = NpyIter_GetInnerLoopSizePtr(iter);
}
else {
self->innerstrides = NULL;
self->innerloopsizeptr = NULL;
}
/* Retrieve read and write flags */
NpyIter_GetReadFlags(iter, self->readflags);
NpyIter_GetWriteFlags(iter, self->writeflags);
return 0;
}
/* Function to create a new instance of NewNpyArrayIterObject */
static PyObject *
npyiter_new(PyTypeObject *subtype, PyObject *NPY_UNUSED(args),
PyObject *NPY_UNUSED(kwds))
{
NewNpyArrayIterObject *self;
/* Allocate memory for NewNpyArrayIterObject */
self = (NewNpyArrayIterObject *)subtype->tp_alloc(subtype, 0);
if (self != NULL) {
self->iter = NULL;
self->nested_child = NULL;
}
return (PyObject *)self;
}
/* Function to convert global flags */
static int
NpyIter_GlobalFlagsConverter(PyObject *flags_in, npy_uint32 *flags)
{
npy_uint32 tmpflags = 0;
int iflags, nflags;
PyObject *f;
char *str = NULL;
Py_ssize_t length = 0;
npy_uint32 flag;
/* Check if flags_in is None or NULL */
if (flags_in == NULL || flags_in == Py_None) {
return 1;
}
if (!PyTuple_Check(flags_in) && !PyList_Check(flags_in)) {
PyErr_SetString(PyExc_ValueError,
"Iterator global flags must be a list or tuple of strings");
return 0;
}
nflags = PySequence_Size(flags_in);
*flags |= tmpflags;
return 1;
}
static int
NpyIter_OpFlagsConverter(PyObject *op_flags_in,
npy_uint32 *op_flags)
{
int iflags, nflags;
npy_uint32 flag;
// 检查输入的 op_flags_in 是否为元组或列表,否则报错
if (!PyTuple_Check(op_flags_in) && !PyList_Check(op_flags_in)) {
PyErr_SetString(PyExc_ValueError,
"op_flags must be a tuple or array of per-op flag-tuples");
return 0;
}
// 获取 op_flags_in 的长度
nflags = PySequence_Size(op_flags_in);
// 将 op_flags 初始化为 0
*op_flags = 0;
}
// 返回成功
return 1;
}
static int
npyiter_convert_op_flags_array(PyObject *op_flags_in,
npy_uint32 *op_flags_array, npy_intp nop)
{
npy_intp iop;
// 检查输入的 op_flags_in 是否为元组或列表,否则报错
if (!PyTuple_Check(op_flags_in) && !PyList_Check(op_flags_in)) {
PyErr_SetString(PyExc_ValueError,
"op_flags must be a tuple or array of per-op flag-tuples");
return 0;
}
// 如果 op_flags_in 的长度不等于 nop,跳转到 try_single_flags 标签处处理
if (PySequence_Size(op_flags_in) != nop) {
goto try_single_flags;
}
// 遍历 op_flags_in 中的每个元素
for (iop = 0; iop < nop; ++iop) {
PyObject *f = PySequence_GetItem(op_flags_in, iop);
if (f == NULL) {
return 0;
}
/* 如果第一个元素是字符串,则尝试作为一组标志 */
if (iop == 0 && (PyBytes_Check(f) || PyUnicode_Check(f))) {
Py_DECREF(f);
goto try_single_flags;
}
// 转换操作标志并存入 op_flags_array[iop] 中
if (NpyIter_OpFlagsConverter(f,
&op_flags_array[iop]) != 1) {
Py_DECREF(f);
return 0;
}
Py_DECREF(f);
}
// 返回成功
return 1;
try_single_flags:
// 尝试将 op_flags_in 转换为单一的操作标志,并复制给所有操作数
if (NpyIter_OpFlagsConverter(op_flags_in,
&op_flags_array[0]) != 1) {
return 0;
}
// 将第一个操作标志复制给其余的操作标志
for (iop = 1; iop < nop; ++iop) {
op_flags_array[iop] = op_flags_array[0];
}
// 返回成功
return 1;
}
static int
npyiter_convert_dtypes(PyObject *op_dtypes_in,
PyArray_Descr **op_dtypes,
npy_intp nop)
{
npy_intp iop;
/*
* 如果输入不是 dtype 的元组,尝试直接将其转换为一个 dtype,并复制给所有操作数。
*/
if ((!PyTuple_Check(op_dtypes_in) && !PyList_Check(op_dtypes_in)) ||
PySequence_Size(op_dtypes_in) != nop) {
// 跳转到 try_single_dtype 标签处处理
goto try_single_dtype;
}
// 遍历 op_dtypes_in 中的每个元素
for (iop = 0; iop < nop; ++iop) {
PyObject *dtype = PySequence_GetItem(op_dtypes_in, iop);
if (dtype == NULL) {
npy_intp i;
for (i = 0; i < iop; ++i ) {
Py_XDECREF(op_dtypes[i]);
}
return 0;
}
// 尝试将对象转换为 dtype 描述符
if (PyArray_DescrConverter2(dtype, &op_dtypes[iop]) != 1) {
npy_intp i;
for (i = 0; i < iop; ++i ) {
Py_XDECREF(op_dtypes[i]);
}
Py_DECREF(dtype);
PyErr_Clear();
// 转到 try_single_dtype 标签处处理
goto try_single_dtype;
}
Py_DECREF(dtype);
}
// 返回成功
return 1;
try_single_dtype:
if (PyArray_DescrConverter2(op_dtypes_in, &op_dtypes[0]) == 1) {
for (iop = 1; iop < nop; ++iop) {
op_dtypes[iop] = op_dtypes[0];
Py_XINCREF(op_dtypes[iop]);
}
return 1;
}
return 0;
static int
npyiter_convert_op_axes(PyObject *op_axes_in, int nop,
int **op_axes, int *oa_ndim)
{
PyObject *a;
int iop;
if ((!PyTuple_Check(op_axes_in) && !PyList_Check(op_axes_in)) ||
PySequence_Size(op_axes_in) != nop) {
PyErr_SetString(PyExc_ValueError,
"op_axes must be a tuple/list matching the number of ops");
return 0; // 返回0表示出错
}
*oa_ndim = -1; // 初始化oa_ndim为-1
/* Copy the tuples into op_axes */
for (iop = 0; iop < nop; ++iop) {
int idim;
a = PySequence_GetItem(op_axes_in, iop); // 获取op_axes_in中的第iop个元素
if (a == NULL) {
return 0; // 如果获取失败,返回0表示出错
}
if (a == Py_None) {
op_axes[iop] = NULL; // 如果元素是None,则在op_axes中对应位置置为NULL
} else {
if (!PyTuple_Check(a) && !PyList_Check(a)) {
PyErr_SetString(PyExc_ValueError,
"Each entry of op_axes must be None "
"or a tuple/list");
Py_DECREF(a);
return 0; // 如果元素不是None也不是元组或列表,则返回0表示出错
}
if (*oa_ndim == -1) {
*oa_ndim = PySequence_Size(a); // 第一次设置oa_ndim为a的长度
if (*oa_ndim > NPY_MAXDIMS) {
PyErr_SetString(PyExc_ValueError,
"Too many dimensions in op_axes");
Py_DECREF(a);
return 0; // 如果oa_ndim超过了NPY_MAXDIMS,则返回0表示出错
}
}
if (PySequence_Size(a) != *oa_ndim) {
PyErr_SetString(PyExc_ValueError,
"Each entry of op_axes must have the same size");
Py_DECREF(a);
return 0; // 如果a的长度与oa_ndim不相等,则返回0表示出错
}
for (idim = 0; idim < *oa_ndim; ++idim) {
PyObject *v = PySequence_GetItem(a, idim); // 获取a中的第idim个元素
if (v == NULL) {
Py_DECREF(a);
return 0; // 如果获取失败,返回0表示出错
}
/* numpy.newaxis is None */
// numpy.newaxis对应的是None
if (v == Py_None) {
op_axes[iop][idim] = -1; // 如果v是None,则在op_axes中设置为-1
}
else {
op_axes[iop][idim] = PyArray_PyIntAsInt(v); // 将v转换为整数并存储在op_axes中
if (op_axes[iop][idim] == -1 &&
PyErr_Occurred()) {
Py_DECREF(a);
Py_DECREF(v);
return 0; // 如果转换失败,则返回0表示出错
}
}
Py_DECREF(v); // 释放v的引用计数
}
}
Py_DECREF(a); // 释放a的引用计数
}
if (*oa_ndim == -1) {
PyErr_SetString(PyExc_ValueError,
"If op_axes is provided, at least one list of axes "
"must be contained within it");
return 0; // 如果oa_ndim仍为-1,则设置异常信息并返回0表示出错
}
return 1; // 成功转换返回1
}
int iop, nop;
/* 定义整数变量 iop 和 nop,用于迭代和存储操作数的数量 */
/* 检查输入参数 op_in 是否为元组或列表 */
if (PyTuple_Check(op_in) || PyList_Check(op_in)) {
nop = PySequence_Size(op_in); // 获取 op_in 中元素的数量
if (nop == 0) {
PyErr_SetString(PyExc_ValueError,
"Must provide at least one operand");
return 0; // 如果没有操作数,返回错误
}
if (nop > NPY_MAXARGS) {
PyErr_SetString(PyExc_ValueError, "Too many operands");
return 0; // 如果操作数超过最大限制,返回错误
}
/* 遍历操作数列表 op_in */
for (iop = 0; iop < nop; ++iop) {
PyObject *item = PySequence_GetItem(op_in, iop); // 获取列表中的每个元素
if (item == NULL) {
npy_intp i;
for (i = 0; i < iop; ++i) {
Py_XDECREF(op[i]); // 如果获取元素失败,释放已获取的元素内存
}
return 0; // 返回错误
}
else if (item == Py_None) {
Py_DECREF(item);
item = NULL; // 如果元素为 None,则释放并置为 NULL
}
/* 将获取的元素转换为 PyArrayObject 类型,存入 op 数组 */
op[iop] = (PyArrayObject *)item;
}
}
else {
nop = 1; // 如果 op_in 不是元组或列表,则操作数为 1
/* 将 op_in 转换为 PyArrayObject 类型,存入 op 数组 */
Py_INCREF(op_in);
op[0] = (PyArrayObject *)op_in;
}
*nop_out = nop; // 将操作数数量存入输出参数 nop_out
/* 处理操作标志 op_flags */
if (op_flags_in == NULL || op_flags_in == Py_None) {
/* 如果未提供 op_flags_in,则根据 op 是否为 NULL 设置默认标志 */
for (iop = 0; iop < nop; ++iop) {
/*
* 默认情况下,将 NULL 操作数设置为只写并标记为分配内存,其他情况设置为只读。
* 若要写入提供的操作数,必须手动指定写标志。
*/
if (op[iop] == NULL) {
op_flags[iop] = NPY_ITER_WRITEONLY | NPY_ITER_ALLOCATE;
}
else {
op_flags[iop] = NPY_ITER_READONLY;
}
}
}
else if (npyiter_convert_op_flags_array(op_flags_in,
op_flags, nop) != 1) {
/* 如果提供了 op_flags_in,则调用函数将其转换为 op_flags 数组 */
for (iop = 0; iop < nop; ++iop) {
Py_XDECREF(op[iop]); // 如果转换失败,释放已获取的元素内存
}
*nop_out = 0;
return 0; // 返回错误
}
/* 现在我们有了标志,将所有操作数转换为数组形式 */
// 遍历操作数数组,处理每个操作数
for (iop = 0; iop < nop; ++iop) {
// 检查操作数是否为非空
if (op[iop] != NULL) {
// 声明一个 PyArrayObject 对象指针
PyArrayObject *ao;
// 初始化 fromanyflags 标志为 0
int fromanyflags = 0;
// 如果操作标志表明可读写或仅写入,则设置 NPY_ARRAY_WRITEBACKIFCOPY 标志
if (op_flags[iop] & (NPY_ITER_READWRITE | NPY_ITER_WRITEONLY)) {
fromanyflags |= NPY_ARRAY_WRITEBACKIFCOPY;
}
// 将 Python 对象 op[iop] 转换为 PyArrayObject 对象
ao = (PyArrayObject *)PyArray_FROM_OF((PyObject *)op[iop],
fromanyflags);
// 如果转换失败,处理异常情况
if (ao == NULL) {
// 如果发生异常且异常匹配 TypeError 类型
if (PyErr_Occurred() &&
PyErr_ExceptionMatches(PyExc_TypeError)) {
// 设置错误消息,指出迭代器操作数标记为可写,但是无法通过 WRITEBACKIFCOPY 进行写入
PyErr_SetString(PyExc_TypeError,
"Iterator operand is flagged as writeable, "
"but is an object which cannot be written "
"back to via WRITEBACKIFCOPY");
}
// 释放之前创建的 PyArrayObject 对象
for (iop = 0; iop < nop; ++iop) {
Py_DECREF(op[iop]);
}
// 设置输出参数 nop_out 为 0,返回失败
*nop_out = 0;
return 0;
}
// 释放原来的 Python 对象 op[iop]
Py_DECREF(op[iop]);
// 将转换后的 PyArrayObject 对象赋值回原来的 op[iop]
op[iop] = ao;
}
}
// 处理完所有操作数后,返回成功
return 1;
}
// 静态函数npyiter_init的实现,用于初始化NpyArrayIter对象
static int
npyiter_init(NewNpyArrayIterObject *self, PyObject *args, PyObject *kwds)
{
// 静态字符串数组,用于解析函数参数
static char *kwlist[] = {"op", "flags", "op_flags", "op_dtypes",
"order", "casting", "op_axes", "itershape",
"buffersize",
NULL};
// 初始化PyObject指针变量
PyObject *op_in = NULL, *op_flags_in = NULL,
*op_dtypes_in = NULL, *op_axes_in = NULL;
// 初始化整型变量和数组
int iop, nop = 0;
PyArrayObject *op[NPY_MAXARGS];
npy_uint32 flags = 0;
NPY_ORDER order = NPY_KEEPORDER;
NPY_CASTING casting = NPY_SAFE_CASTING;
npy_uint32 op_flags[NPY_MAXARGS];
PyArray_Descr *op_request_dtypes[NPY_MAXARGS];
int oa_ndim = -1;
int op_axes_arrays[NPY_MAXARGS][NPY_MAXDIMS];
int *op_axes[NPY_MAXARGS];
PyArray_Dims itershape = {NULL, -1};
int buffersize = 0;
// 如果迭代器已经初始化,则返回错误
if (self->iter != NULL) {
PyErr_SetString(PyExc_ValueError,
"Iterator was already initialized");
return -1;
}
// 解析输入参数并进行类型转换,若解析失败则返回错误
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&OOO&O&OO&i:nditer", kwlist,
&op_in,
NpyIter_GlobalFlagsConverter, &flags,
&op_flags_in,
&op_dtypes_in,
PyArray_OrderConverter, &order,
PyArray_CastingConverter, &casting,
&op_axes_in,
PyArray_OptionalIntpConverter, &itershape,
&buffersize)) {
npy_free_cache_dim_obj(itershape);
return -1;
}
/* Set the dtypes and ops to all NULL to start */
// 将op_request_dtypes数组初始化为NULL
memset(op_request_dtypes, 0, sizeof(op_request_dtypes));
/* op and op_flags */
// 转换操作数和操作标志
if (npyiter_convert_ops(op_in, op_flags_in, op, op_flags, &nop)
!= 1) {
goto fail;
}
/* op_request_dtypes */
// 转换操作数据类型
if (op_dtypes_in != NULL && op_dtypes_in != Py_None &&
npyiter_convert_dtypes(op_dtypes_in,
op_request_dtypes, nop) != 1) {
goto fail;
}
/* op_axes */
// 转换操作轴信息
if (op_axes_in != NULL && op_axes_in != Py_None) {
// 初始化op_axes数组指向op_axes_arrays的各个数组
for (iop = 0; iop < nop; ++iop) {
op_axes[iop] = op_axes_arrays[iop];
}
// 执行操作轴转换函数
if (npyiter_convert_op_axes(op_axes_in, nop,
op_axes, &oa_ndim) != 1) {
goto fail;
}
}
// 检查itershape的长度,与op_axes的维度信息进行匹配
if (itershape.len != -1) {
if (oa_ndim == -1) {
oa_ndim = itershape.len;
memset(op_axes, 0, sizeof(op_axes[0]) * nop);
}
else if (oa_ndim != itershape.len) {
PyErr_SetString(PyExc_ValueError,
"'op_axes' and 'itershape' must have the same number "
"of entries equal to the iterator ndim");
goto fail;
}
}
// 使用 NpyIter_AdvancedNew 函数创建高级迭代器对象,并初始化 self->iter
self->iter = NpyIter_AdvancedNew(nop, op, flags, order, casting, op_flags,
op_request_dtypes,
oa_ndim, oa_ndim >= 0 ? op_axes : NULL,
itershape.ptr,
buffersize);
// 检查 self->iter 是否为 NULL,如果是则跳转到失败处理代码块
if (self->iter == NULL) {
goto fail;
}
/* 缓存一些值,供成员函数使用 */
// 如果 npyiter_cache_values 函数返回值小于 0,则跳转到失败处理代码块
if (npyiter_cache_values(self) < 0) {
goto fail;
}
// 检查 self->iter 的迭代大小是否为 0,根据结果设置 self->started 和 self->finished
if (NpyIter_GetIterSize(self->iter) == 0) {
self->started = 1;
self->finished = 1;
}
else {
self->started = 0;
self->finished = 0;
}
// 释放 itershape 所持有的对象引用
npy_free_cache_dim_obj(itershape);
/* 释放对 ops 和 dtypes 的引用 */
// 遍历释放 op 和 op_request_dtypes 数组中的引用对象
for (iop = 0; iop < nop; ++iop) {
Py_XDECREF(op[iop]);
Py_XDECREF(op_request_dtypes[iop]);
}
// 成功执行,返回 0 表示没有错误
return 0;
fail:
// 释放缓存中的迭代形状对象
npy_free_cache_dim_obj(itershape);
// 循环释放操作数数组中的对象引用
for (iop = 0; iop < nop; ++iop) {
Py_XDECREF(op[iop]);
Py_XDECREF(op_request_dtypes[iop]);
}
// 返回错误状态
return -1;
}
NPY_NO_EXPORT PyObject *
NpyIter_NestedIters(PyObject *NPY_UNUSED(self),
PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"op", "axes", "flags", "op_flags",
"op_dtypes", "order",
"casting", "buffersize",
NULL};
PyObject *op_in = NULL, *axes_in = NULL,
*op_flags_in = NULL, *op_dtypes_in = NULL;
int iop, nop = 0, inest, nnest = 0;
PyArrayObject *op[NPY_MAXARGS];
npy_uint32 flags = 0, flags_inner;
NPY_ORDER order = NPY_KEEPORDER;
NPY_CASTING casting = NPY_SAFE_CASTING;
npy_uint32 op_flags[NPY_MAXARGS], op_flags_inner[NPY_MAXARGS];
PyArray_Descr *op_request_dtypes[NPY_MAXARGS],
*op_request_dtypes_inner[NPY_MAXARGS];
int op_axes_data[NPY_MAXDIMS];
int *nested_op_axes[NPY_MAXDIMS];
int nested_naxes[NPY_MAXDIMS], iaxes, naxes;
int negones[NPY_MAXDIMS];
char used_axes[NPY_MAXDIMS];
int buffersize = 0;
PyObject *ret = NULL;
// 解析传入参数并进行类型转换
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O&OOO&O&i", kwlist,
&op_in,
&axes_in,
NpyIter_GlobalFlagsConverter, &flags,
&op_flags_in,
&op_dtypes_in,
PyArray_OrderConverter, &order,
PyArray_CastingConverter, &casting,
&buffersize)) {
return NULL;
}
/* axes */
// 检查传入的 axes 是否为元组或列表
if (!PyTuple_Check(axes_in) && !PyList_Check(axes_in)) {
PyErr_SetString(PyExc_ValueError,
"axes must be a tuple of axis arrays");
return NULL;
}
// 获取传入 axes 的长度
nnest = PySequence_Size(axes_in);
// axes 至少需要两个条目才能进行嵌套迭代
if (nnest < 2) {
PyErr_SetString(PyExc_ValueError,
"axes must have at least 2 entries for nested iteration");
return NULL;
}
// 初始化轴数计数器和轴使用标志数组
naxes = 0;
memset(used_axes, 0, NPY_MAXDIMS);
for (inest = 0; inest < nnest; ++inest) {
// 从 axes_in 序列中获取第 inest 个元素
PyObject *item = PySequence_GetItem(axes_in, inest);
npy_intp i;
// 如果获取失败,返回空指针
if (item == NULL) {
return NULL;
}
// 检查 item 是否为元组或列表类型,如果不是,返回错误信息并释放 item
if (!PyTuple_Check(item) && !PyList_Check(item)) {
PyErr_SetString(PyExc_ValueError,
"Each item in axes must be a an integer tuple");
Py_DECREF(item);
return NULL;
}
// 记录当前 item 的长度到 nested_naxes[inest]
nested_naxes[inest] = PySequence_Size(item);
// 检查当前轴数与之前的总轴数是否超过 NPY_MAXDIMS,如果是,返回错误信息并释放 item
if (naxes + nested_naxes[inest] > NPY_MAXDIMS) {
PyErr_SetString(PyExc_ValueError,
"Too many axes given");
Py_DECREF(item);
return NULL;
}
// 遍历 item 中的元素
for (i = 0; i < nested_naxes[inest]; ++i) {
// 获取 item 中第 i 个元素
PyObject *v = PySequence_GetItem(item, i);
npy_intp axis;
// 如果获取失败,释放 item 并返回空指针
if (v == NULL) {
Py_DECREF(item);
return NULL;
}
// 将 v 转换为长整型并赋值给 axis
axis = PyLong_AsLong(v);
Py_DECREF(v);
// 检查 axis 是否在有效范围内,如果不是,返回错误信息并释放 item
if (axis < 0 || axis >= NPY_MAXDIMS) {
PyErr_SetString(PyExc_ValueError,
"An axis is out of bounds");
Py_DECREF(item);
return NULL;
}
// 检查当前 axis 是否已被使用,如果是,返回错误信息并释放 item
if (used_axes[axis] != 0) {
PyErr_SetString(PyExc_ValueError,
"An axis is used more than once");
Py_DECREF(item);
return NULL;
}
// 标记当前 axis 已被使用
used_axes[axis] = 1;
// 将 axis 添加到 op_axes_data 中,从 naxes 开始的位置
op_axes_data[naxes+i] = axis;
}
// 将当前 op_axes_data 的子数组赋值给 nested_op_axes[inest]
nested_op_axes[inest] = &op_axes_data[naxes];
// 更新总轴数 naxes
naxes += nested_naxes[inest];
// 释放 item
Py_DECREF(item);
}
/* op and op_flags */
// 调用 npyiter_convert_ops 函数处理 op 和 op_flags
if (npyiter_convert_ops(op_in, op_flags_in, op, op_flags, &nop)
!= 1) {
return NULL;
}
/* Set the dtypes to all NULL to start as well */
// 将 op_request_dtypes 数组初始化为全 NULL
memset(op_request_dtypes, 0, sizeof(op_request_dtypes[0])*nop);
// 将 op_request_dtypes_inner 数组初始化为全 NULL
memset(op_request_dtypes_inner, 0,
sizeof(op_request_dtypes_inner[0])*nop);
/* op_request_dtypes */
// 如果 op_dtypes_in 不为空且不是 Py_None,则调用 npyiter_convert_dtypes 处理 op_dtypes_in
if (op_dtypes_in != NULL && op_dtypes_in != Py_None &&
npyiter_convert_dtypes(op_dtypes_in,
op_request_dtypes, nop) != 1) {
goto fail;
}
// 创建一个包含 nnest 个元素的新元组 ret
ret = PyTuple_New(nnest);
// 如果创建失败,跳转到 fail 标签处理错误
if (ret == NULL) {
goto fail;
}
/* For broadcasting allocated arrays */
// 将 negones 数组的前 naxes 个元素初始化为 -1
for (iaxes = 0; iaxes < naxes; ++iaxes) {
negones[iaxes] = -1;
}
/*
* Clear any unnecessary ALLOCATE flags, so we can use them
* to indicate exactly the allocated outputs. Also, separate
* the inner loop flags.
*/
for (iop = 0; iop < nop; ++iop) {
// 检查是否需要分配内存,并且操作数组不为NULL时,清除分配标志位
if ((op_flags[iop] & NPY_ITER_ALLOCATE) && op[iop] != NULL) {
op_flags[iop] &= ~NPY_ITER_ALLOCATE;
}
/*
* 清除允许在内部循环中进行复制或输出分配的标志位。
*/
op_flags_inner[iop] = op_flags[iop] & ~(NPY_ITER_COPY |
NPY_ITER_UPDATEIFCOPY |
NPY_ITER_ALLOCATE);
/*
* 如果启用了缓冲,并且没有复制操作,
* 则清除 nbo_aligned 标志位并且去除外部循环的数据类型。
*/
if ((flags & (NPY_ITER_BUFFERED)) &&
!(op_flags[iop] & (NPY_ITER_COPY |
NPY_ITER_UPDATEIFCOPY |
NPY_ITER_ALLOCATE))) {
op_flags[iop] &= ~(NPY_ITER_NBO | NPY_ITER_ALIGNED | NPY_ITER_CONTIG);
op_request_dtypes_inner[iop] = op_request_dtypes[iop];
op_request_dtypes[iop] = NULL;
}
}
/* 只有内部循环可以使用缓冲,而且没有内部标志 */
flags_inner = flags & ~NPY_ITER_COMMON_DTYPE;
flags &= ~(NPY_ITER_EXTERNAL_LOOP |
NPY_ITER_BUFFERED);
}
/* 释放对操作数组和数据类型的引用 */
for (iop = 0; iop < nop; ++iop) {
Py_XDECREF(op[iop]);
Py_XDECREF(op_request_dtypes[iop]);
Py_XDECREF(op_request_dtypes_inner[iop]);
}
/* 设置嵌套子引用 */
for (inest = 0; inest < nnest-1; ++inest) {
NewNpyArrayIterObject *iter;
iter = (NewNpyArrayIterObject *)PyTuple_GET_ITEM(ret, inest);
/*
* 指示在每次迭代步骤中重置哪个迭代器的基指针。
*/
iter->nested_child =
(NewNpyArrayIterObject *)PyTuple_GET_ITEM(ret, inest+1);
Py_INCREF(iter->nested_child);
/*
* 需要进行嵌套重置,以便所有迭代器指向正确的数据。
*/
if (NpyIter_ResetBasePointers(iter->nested_child->iter,
iter->dataptrs, NULL) != NPY_SUCCEED) {
Py_DECREF(ret);
return NULL;
}
}
return ret;
/*
* Free resources held by the iterator upon encountering a failure condition.
* This function decrements references to Python objects and returns NULL.
*/
fail:
for (iop = 0; iop < nop; ++iop) {
Py_XDECREF(op[iop]); // Decrement reference count for op[iop]
Py_XDECREF(op_request_dtypes[iop]); // Decrement reference count for op_request_dtypes[iop]
Py_XDECREF(op_request_dtypes_inner[iop]); // Decrement reference count for op_request_dtypes_inner[iop]
}
return NULL; // Return NULL to indicate failure
}
/*
* Deallocates memory and resources held by a NewNpyArrayIterObject instance.
* If an iterator is present, it handles error handling and cleanup of resources.
*/
static void
npyiter_dealloc(NewNpyArrayIterObject *self)
{
if (self->iter) {
/* Store current exception state to preserve it */
PyObject *exc, *val, *tb;
PyErr_Fetch(&exc, &val, &tb);
// Check if writeback is needed
if (npyiter_has_writeback(self->iter)) {
// Issue a runtime warning if temporary data hasn't been written back
if (PyErr_WarnEx(PyExc_RuntimeWarning,
"Temporary data has not been written back to one of the "
"operands. Typically nditer is used as a context manager "
"otherwise 'close' must be called before reading iteration "
"results.", 1) < 0) {
PyObject *s;
s = PyUnicode_FromString("npyiter_dealloc");
if (s) {
PyErr_WriteUnraisable(s); // Write an unraisable error with a custom message
Py_DECREF(s);
}
else {
PyErr_WriteUnraisable(Py_None); // Write an unraisable error with a default message
}
}
}
// Deallocate the iterator
if (!NpyIter_Deallocate(self->iter)) {
PyErr_WriteUnraisable(Py_None); // Write an unraisable error if deallocation fails
}
// Reset instance variables
self->iter = NULL;
Py_XDECREF(self->nested_child); // Decrement reference count for nested_child
self->nested_child = NULL;
// Restore previous exception state
PyErr_Restore(exc, val, tb);
}
// Free memory allocated for the object
Py_TYPE(self)->tp_free((PyObject*)self);
}
/*
* Resets base pointers for nested iterators and checks for success.
* Updates the status of iteration for the current iterator.
* Returns NPY_SUCCEED on success, NPY_FAIL on failure.
*/
static int
npyiter_resetbasepointers(NewNpyArrayIterObject *self)
{
while (self->nested_child) {
// Reset base pointers for the nested iterator
if (NpyIter_ResetBasePointers(self->nested_child->iter,
self->dataptrs, NULL) != NPY_SUCCEED) {
return NPY_FAIL; // Return failure status if reset fails
}
self = self->nested_child;
// Update iteration status based on iterator size
if (NpyIter_GetIterSize(self->iter) == 0) {
self->started = 1;
self->finished = 1;
}
else {
self->started = 0;
self->finished = 0;
}
}
return NPY_SUCCEED; // Return success status
}
/*
* Resets the iterator to its initial state.
* Checks for validity of the iterator and performs reset operations.
* Returns None on success, raises ValueError on invalid iterator.
*/
static PyObject *
npyiter_reset(NewNpyArrayIterObject *self, PyObject *NPY_UNUSED(args))
{
// Check if iterator is valid
if (self->iter == NULL) {
PyErr_SetString(PyExc_ValueError,
"Iterator is invalid");
return NULL; // Return NULL indicating error
}
// Reset the iterator
if (NpyIter_Reset(self->iter, NULL) != NPY_SUCCEED) {
return NULL; // Return NULL indicating error
}
// Update iteration status based on iterator size
if (NpyIter_GetIterSize(self->iter) == 0) {
self->started = 1;
self->finished = 1;
}
else {
self->started = 0;
self->finished = 0;
}
// Get multi-index function if not already retrieved
if (self->get_multi_index == NULL && NpyIter_HasMultiIndex(self->iter)) {
self->get_multi_index = NpyIter_GetGetMultiIndex(self->iter, NULL);
}
/* If there is nesting, reset nested iterators */
if (npyiter_resetbasepointers(self) != NPY_SUCCEED) {
return NULL; // Return NULL indicating error
}
Py_RETURN_NONE; // Return Python None object on success
}
/*
* 复制给定的 NpyArray 迭代器对象并返回其 Python 对象表示
*/
PyObject *npyiter_copy(NewNpyArrayIterObject *self, PyObject *NPY_UNUSED(args))
{
NewNpyArrayIterObject *iter;
// 检查迭代器是否有效,若无效则返回 ValueError 异常
if (self->iter == NULL) {
PyErr_SetString(PyExc_ValueError,
"Iterator is invalid");
return NULL;
}
/* 分配新的迭代器对象 */
iter = (NewNpyArrayIterObject *)npyiter_new(&NpyIter_Type, NULL, NULL);
if (iter == NULL) {
return NULL;
}
/* 复制 C 语言迭代器 */
iter->iter = NpyIter_Copy(self->iter);
if (iter->iter == NULL) {
Py_DECREF(iter);
return NULL;
}
/* 缓存一些值以供成员函数使用 */
if (npyiter_cache_values(iter) < 0) {
Py_DECREF(iter);
return NULL;
}
// 复制起始和结束标记
iter->started = self->started;
iter->finished = self->finished;
return (PyObject *)iter;
}
/*
* 迭代器的下一个操作,返回一个布尔值的 Python 对象表示
*/
static PyObject *
npyiter_iternext(NewNpyArrayIterObject *self, PyObject *NPY_UNUSED(args))
{
// 检查迭代器是否有效,迭代函数是否可用,并且迭代未完成且成功迭代下一个元素
if (self->iter != NULL && self->iternext != NULL &&
!self->finished && self->iternext(self->iter)) {
/* 如果有嵌套迭代,需要重置嵌套的迭代器 */
if (npyiter_resetbasepointers(self) != NPY_SUCCEED) {
return NULL;
}
Py_RETURN_TRUE;
}
else {
// 如果发生错误,返回 NULL
if (PyErr_Occurred()) {
/* 类型转换错误,缓冲区将在重置或释放时清理 */
return NULL;
}
// 设置迭代完成标记并返回 False
self->finished = 1;
Py_RETURN_FALSE;
}
}
/*
* 移除迭代器中的指定轴
*/
static PyObject *
npyiter_remove_axis(NewNpyArrayIterObject *self, PyObject *args)
{
int axis = 0;
// 检查迭代器是否有效,若无效则返回 ValueError 异常
if (self->iter == NULL) {
PyErr_SetString(PyExc_ValueError,
"Iterator is invalid");
return NULL;
}
// 解析参数,获取要移除的轴的索引
if (!PyArg_ParseTuple(args, "i:remove_axis", &axis)) {
return NULL;
}
// 在迭代器中移除指定的轴
if (NpyIter_RemoveAxis(self->iter, axis) != NPY_SUCCEED) {
return NULL;
}
/* 移除轴后使缓存的值无效 */
if (npyiter_cache_values(self) < 0) {
return NULL;
}
/* 移除轴也会重置迭代器 */
if (NpyIter_GetIterSize(self->iter) == 0) {
self->started = 1;
self->finished = 1;
}
else {
self->started = 0;
self->finished = 0;
}
Py_RETURN_NONE;
}
/*
* 移除迭代器中的多重索引
*/
static PyObject *
npyiter_remove_multi_index(
NewNpyArrayIterObject *self, PyObject *NPY_UNUSED(args))
{
// 检查迭代器是否有效,若无效则返回 ValueError 异常
if (self->iter == NULL) {
PyErr_SetString(PyExc_ValueError,
"Iterator is invalid");
return NULL;
}
// 移除迭代器中的多重索引
NpyIter_RemoveMultiIndex(self->iter);
/* 移除多重索引后使缓存的值无效 */
npyiter_cache_values(self);
/* 移除多重索引也会重置迭代器 */
if (NpyIter_GetIterSize(self->iter) == 0) {
self->started = 1;
self->finished = 1;
}
else {
self->started = 0;
self->finished = 0;
}
Py_RETURN_NONE;
}
/*
* 启用迭代器的外部循环模式
*/
static PyObject *
npyiter_enable_external_loop(
NewNpyArrayIterObject *self, PyObject *NPY_UNUSED(args))
{
// 检查迭代器是否为 NULL,如果是则设置一个值错误异常并返回 NULL
if (self->iter == NULL) {
PyErr_SetString(PyExc_ValueError,
"Iterator is invalid");
return NULL;
}
// 启用迭代器的外部循环功能
NpyIter_EnableExternalLoop(self->iter);
/* EnableExternalLoop invalidates cached values */
// 启用外部循环功能会使缓存的数值无效
npyiter_cache_values(self);
/* EnableExternalLoop also resets the iterator */
// 启用外部循环功能也会重置迭代器
// 如果迭代器的大小为 0,则将 started 和 finished 标记为 1
if (NpyIter_GetIterSize(self->iter) == 0) {
self->started = 1;
self->finished = 1;
}
// 否则将 started 和 finished 标记为 0
else {
self->started = 0;
self->finished = 0;
}
// 返回 Python 中的 None 对象,表示成功执行但不返回任何值
Py_RETURN_NONE;
static PyObject *
npyiter_debug_print(NewNpyArrayIterObject *self, PyObject *NPY_UNUSED(args))
{
// 检查迭代器是否存在,如果存在则调用 NpyIter_DebugPrint 输出调试信息
if (self->iter != NULL) {
NpyIter_DebugPrint(self->iter);
}
// 如果迭代器不存在,打印信息表示迭代器为空
else {
printf("Iterator: (nil)\n");
}
// 返回 None
Py_RETURN_NONE;
}
NPY_NO_EXPORT PyObject *
npyiter_seq_item(NewNpyArrayIterObject *self, Py_ssize_t i);
static PyObject *
npyiter_value_get(NewNpyArrayIterObject *self, void *NPY_UNUSED(ignored))
{
PyObject *ret;
npy_intp iop, nop;
// 检查迭代器是否为 NULL 或者已经结束
if (self->iter == NULL || self->finished) {
// 设置错误信息并返回 NULL
PyErr_SetString(PyExc_ValueError,
"Iterator is past the end");
return NULL;
}
nop = NpyIter_GetNOp(self->iter);
/* Return an array or tuple of arrays with the values */
// 如果操作数个数为 1,则调用 npyiter_seq_item 获取第一个元素
if (nop == 1) {
ret = npyiter_seq_item(self, 0);
}
// 否则创建一个元组,并逐个获取每个操作数的值
else {
ret = PyTuple_New(nop);
if (ret == NULL) {
return NULL;
}
for (iop = 0; iop < nop; ++iop) {
PyObject *a = npyiter_seq_item(self, iop);
if (a == NULL) {
Py_DECREF(ret);
return NULL;
}
PyTuple_SET_ITEM(ret, iop, a);
}
}
return ret;
}
static PyObject *
npyiter_operands_get(NewNpyArrayIterObject *self, void *NPY_UNUSED(ignored))
{
PyObject *ret;
npy_intp iop, nop;
PyArrayObject **operands;
// 检查迭代器是否为 NULL
if (self->iter == NULL) {
// 设置错误信息并返回 NULL
PyErr_SetString(PyExc_ValueError,
"Iterator is invalid");
return NULL;
}
nop = NpyIter_GetNOp(self->iter);
operands = self->operands;
// 创建一个元组,并将每个操作数对象添加到元组中
ret = PyTuple_New(nop);
if (ret == NULL) {
return NULL;
}
for (iop = 0; iop < nop; ++iop) {
PyObject *operand = (PyObject *)operands[iop];
Py_INCREF(operand);
PyTuple_SET_ITEM(ret, iop, operand);
}
return ret;
}
static PyObject *
npyiter_itviews_get(NewNpyArrayIterObject *self, void *NPY_UNUSED(ignored))
{
PyObject *ret;
npy_intp iop, nop;
// 检查迭代器是否为 NULL
if (self->iter == NULL) {
// 设置错误信息并返回 NULL
PyErr_SetString(PyExc_ValueError,
"Iterator is invalid");
return NULL;
}
nop = NpyIter_GetNOp(self->iter);
// 创建一个元组,并将每个迭代视图对象添加到元组中
ret = PyTuple_New(nop);
if (ret == NULL) {
return NULL;
}
for (iop = 0; iop < nop; ++iop) {
PyArrayObject *view = NpyIter_GetIterView(self->iter, iop);
if (view == NULL) {
Py_DECREF(ret);
return NULL;
}
PyTuple_SET_ITEM(ret, iop, (PyObject *)view);
}
return ret;
}
static PyObject *
npyiter_next(NewNpyArrayIterObject *self)
{
// 检查迭代器是否为 NULL,或者迭代过程已经结束,或者 iternext 函数为空
if (self->iter == NULL || self->iternext == NULL ||
self->finished) {
// 返回 NULL,表示迭代结束或者出现错误
return NULL;
}
/*
* Use the started flag for the Python iteration protocol to work
* when buffering is enabled.
*/
// 这里通常用来实现迭代器的下一个值获取逻辑,但是具体细节未给出,需要根据实际情况补充实现
// 返回下一个迭代值,具体逻辑应根据实际需求补充
}
# 检查迭代器是否已经开始迭代
if (self->started) {
# 如果已经开始迭代,尝试获取下一个元素
if (!self->iternext(self->iter)) {
/*
* 如果出现类型转换错误,可能会在这里设置错误(或者没有错误导致 StopIteration)。
* 缓冲区可能只能在稍后清理。
*/
# 如果无法获取下一个元素,标记迭代结束
self->finished = 1;
# 返回空指针表示迭代结束
return NULL;
}
/* 如果存在嵌套迭代器,应该重置这些嵌套迭代器 */
# 如果有嵌套迭代器,重置它们的基指针
if (npyiter_resetbasepointers(self) != NPY_SUCCEED) {
# 如果重置基指针失败,返回空指针
return NULL;
}
}
# 设置迭代器已经开始迭代的标志
self->started = 1;
# 返回当前迭代器位置的值
return npyiter_value_get(self, NULL);
# 获取迭代器的形状信息并返回作为 Python 元组
static PyObject *
npyiter_shape_get(NewNpyArrayIterObject *self, void *NPY_UNUSED(ignored))
{
npy_intp ndim, shape[NPY_MAXDIMS]; // 定义变量:维度数和形状数组
if (self->iter == NULL || self->finished) { // 检查迭代器是否为空或已完成
PyErr_SetString(PyExc_ValueError,
"Iterator is past the end"); // 设置异常信息并返回 NULL
return NULL;
}
if (NpyIter_GetShape(self->iter, shape) == NPY_SUCCEED) { // 获取迭代器的形状信息
ndim = NpyIter_GetNDim(self->iter); // 获取迭代器的维度数
return PyArray_IntTupleFromIntp(ndim, shape); // 将形状数组转换为 Python 元组并返回
}
return NULL; // 获取形状信息失败,返回 NULL
}
# 获取迭代器的多重索引并返回作为 Python 元组
static PyObject *
npyiter_multi_index_get(NewNpyArrayIterObject *self, void *NPY_UNUSED(ignored))
{
npy_intp ndim, multi_index[NPY_MAXDIMS]; // 定义变量:维度数和多重索引数组
if (self->iter == NULL || self->finished) { // 检查迭代器是否为空或已完成
PyErr_SetString(PyExc_ValueError,
"Iterator is past the end"); // 设置异常信息并返回 NULL
return NULL;
}
if (self->get_multi_index != NULL) { // 检查是否定义了获取多重索引的函数
ndim = NpyIter_GetNDim(self->iter); // 获取迭代器的维度数
self->get_multi_index(self->iter, multi_index); // 调用获取多重索引的函数
return PyArray_IntTupleFromIntp(ndim, multi_index); // 将多重索引数组转换为 Python 元组并返回
}
else { // 若未定义获取多重索引的函数
if (!NpyIter_HasMultiIndex(self->iter)) { // 检查迭代器是否未跟踪多重索引
PyErr_SetString(PyExc_ValueError,
"Iterator is not tracking a multi-index"); // 设置异常信息并返回 NULL
return NULL;
}
else if (NpyIter_HasDelayedBufAlloc(self->iter)) { // 检查迭代器是否使用了延迟缓冲区分配
PyErr_SetString(PyExc_ValueError,
"Iterator construction used delayed buffer allocation, "
"and no reset has been done yet"); // 设置异常信息并返回 NULL
return NULL;
}
else {
PyErr_SetString(PyExc_ValueError,
"Iterator is in an invalid state"); // 其他情况下设置异常信息并返回 NULL
return NULL;
}
}
}
# 设置迭代器的多重索引
static int
npyiter_multi_index_set(
NewNpyArrayIterObject *self, PyObject *value, void *NPY_UNUSED(ignored))
{
npy_intp idim, ndim, multi_index[NPY_MAXDIMS]; // 定义变量:单个索引、维度数和多重索引数组
if (value == NULL) { // 检查值是否为空
PyErr_SetString(PyExc_AttributeError,
"Cannot delete nditer multi_index"); // 设置异常信息并返回 -1
return -1;
}
if (self->iter == NULL) { // 检查迭代器是否为空
PyErr_SetString(PyExc_ValueError,
"Iterator is invalid"); // 设置异常信息并返回 -1
return -1;
}
# 检查迭代器是否具有多索引功能
if (NpyIter_HasMultiIndex(self->iter)) {
# 获取迭代器的维度数
ndim = NpyIter_GetNDim(self->iter);
# 检查传入的值是否为序列类型
if (!PySequence_Check(value)) {
PyErr_SetString(PyExc_ValueError,
"multi_index must be set with a sequence");
return -1;
}
# 检查传入的序列长度是否与迭代器的维度数一致
if (PySequence_Size(value) != ndim) {
PyErr_SetString(PyExc_ValueError,
"Wrong number of indices");
return -1;
}
# 遍历每个维度,从序列中获取对应的索引值并存入multi_index数组
for (idim = 0; idim < ndim; ++idim) {
PyObject *v = PySequence_GetItem(value, idim);
multi_index[idim] = PyLong_AsLong(v);
Py_DECREF(v);
# 检查转换过程中是否出现错误
if (error_converting(multi_index[idim])) {
return -1;
}
}
# 将迭代器定位到指定的多索引位置
if (NpyIter_GotoMultiIndex(self->iter, multi_index) != NPY_SUCCEED) {
return -1;
}
# 重置迭代器的状态
self->started = 0;
self->finished = 0;
/* 如果存在嵌套迭代器,应该重置嵌套的迭代器指针 */
if (npyiter_resetbasepointers(self) != NPY_SUCCEED) {
return -1;
}
# 操作成功,返回0表示没有错误
return 0;
}
else {
# 如果迭代器不支持多索引,则返回错误信息
PyErr_SetString(PyExc_ValueError,
"Iterator is not tracking a multi-index");
return -1;
}
static PyObject *
npyiter_index_get(NewNpyArrayIterObject *self, void *NPY_UNUSED(ignored))
{
// 检查迭代器是否为空或已经结束
if (self->iter == NULL || self->finished) {
PyErr_SetString(PyExc_ValueError,
"Iterator is past the end");
return NULL;
}
// 检查迭代器是否具有索引
if (NpyIter_HasIndex(self->iter)) {
// 获取迭代器当前索引值并返回作为 Python 整数对象
npy_intp ind = *NpyIter_GetIndexPtr(self->iter);
return PyLong_FromLong(ind);
}
else {
PyErr_SetString(PyExc_ValueError,
"Iterator does not have an index");
return NULL;
}
}
static int
npyiter_index_set(
NewNpyArrayIterObject *self, PyObject *value, void *NPY_UNUSED(ignored))
{
// 检查是否试图删除迭代器的索引
if (value == NULL) {
PyErr_SetString(PyExc_AttributeError,
"Cannot delete nditer index");
return -1;
}
// 检查迭代器是否为空
if (self->iter == NULL) {
PyErr_SetString(PyExc_ValueError,
"Iterator is invalid");
return -1;
}
// 检查迭代器是否具有索引
if (NpyIter_HasIndex(self->iter)) {
npy_intp ind;
// 尝试将 Python 对象转换为长整型索引值
ind = PyLong_AsLong(value);
if (error_converting(ind)) {
return -1;
}
// 跳转至指定索引位置
if (NpyIter_GotoIndex(self->iter, ind) != NPY_SUCCEED) {
return -1;
}
// 重置迭代器状态
self->started = 0;
self->finished = 0;
/* 如果存在嵌套迭代器,则需要重置嵌套迭代器的基本指针 */
if (npyiter_resetbasepointers(self) != NPY_SUCCEED) {
return -1;
}
return 0;
}
else {
PyErr_SetString(PyExc_ValueError,
"Iterator does not have an index");
return -1;
}
}
static PyObject *
npyiter_iterindex_get(NewNpyArrayIterObject *self, void *NPY_UNUSED(ignored))
{
// 检查迭代器是否为空或已经结束
if (self->iter == NULL || self->finished) {
PyErr_SetString(PyExc_ValueError,
"Iterator is past the end");
return NULL;
}
// 返回当前迭代器的迭代索引作为 Python 整数对象
return PyLong_FromLong(NpyIter_GetIterIndex(self->iter));
}
static int
npyiter_iterindex_set(
NewNpyArrayIterObject *self, PyObject *value, void *NPY_UNUSED(ignored))
{
npy_intp iterindex;
// 检查是否试图删除迭代器的迭代索引
if (value == NULL) {
PyErr_SetString(PyExc_AttributeError,
"Cannot delete nditer iterindex");
return -1;
}
// 检查迭代器是否为空
if (self->iter == NULL) {
PyErr_SetString(PyExc_ValueError,
"Iterator is invalid");
return -1;
}
// 尝试将 Python 对象转换为长整型迭代索引值
iterindex = PyLong_AsLong(value);
if (error_converting(iterindex)) {
return -1;
}
// 跳转至指定迭代索引位置
if (NpyIter_GotoIterIndex(self->iter, iterindex) != NPY_SUCCEED) {
return -1;
}
// 重置迭代器状态
self->started = 0;
self->finished = 0;
/* 如果存在嵌套迭代器,则需要重置嵌套迭代器的基本指针 */
if (npyiter_resetbasepointers(self) != NPY_SUCCEED) {
return -1;
}
return 0;
}
static PyObject *
npyiter_iterrange_get(NewNpyArrayIterObject *self, void *NPY_UNUSED(ignored))
{
npy_intp istart = 0, iend = 0;
PyObject *ret;
# 检查迭代器是否为NULL,如果是则抛出值错误异常并返回NULL
if (self->iter == NULL) {
PyErr_SetString(PyExc_ValueError,
"Iterator is invalid");
return NULL;
}
# 获取迭代器的索引范围,存储在istart和iend中
NpyIter_GetIterIndexRange(self->iter, &istart, &iend);
# 创建一个包含两个元素的元组对象ret
ret = PyTuple_New(2);
if (ret == NULL) {
return NULL; # 如果创建失败,则返回NULL
}
# 将istart和iend分别转换为Python的长整型对象,并设置到元组ret的对应位置
PyTuple_SET_ITEM(ret, 0, PyLong_FromLong(istart));
PyTuple_SET_ITEM(ret, 1, PyLong_FromLong(iend));
# 返回构建好的元组对象ret
return ret;
static int
npyiter_iterrange_set(
NewNpyArrayIterObject *self, PyObject *value, void *NPY_UNUSED(ignored))
{
npy_intp istart = 0, iend = 0;
if (value == NULL) {
// 如果传入的值为 NULL,设置错误信息并返回 -1
PyErr_SetString(PyExc_AttributeError,
"Cannot delete nditer iterrange");
return -1;
}
if (self->iter == NULL) {
// 如果迭代器为 NULL,设置错误信息并返回 -1
PyErr_SetString(PyExc_ValueError,
"Iterator is invalid");
return -1;
}
// 解析传入的 value,期望格式为 "nn",分别存入 istart 和 iend
if (!PyArg_ParseTuple(value, "nn", &istart, &iend)) {
return -1;
}
// 调用 NpyIter_ResetToIterIndexRange 重置迭代器范围,如果失败则返回 -1
if (NpyIter_ResetToIterIndexRange(self->iter, istart, iend, NULL)
!= NPY_SUCCEED) {
return -1;
}
// 根据 istart 和 iend 的关系设置 started 和 finished
if (istart < iend) {
self->started = self->finished = 0;
}
else {
self->started = self->finished = 1;
}
// 如果 get_multi_index 为 NULL 且迭代器支持多索引,获取多索引函数
if (self->get_multi_index == NULL && NpyIter_HasMultiIndex(self->iter)) {
self->get_multi_index = NpyIter_GetGetMultiIndex(self->iter, NULL);
}
/* 如果存在嵌套迭代器,应当重置嵌套迭代器的基础指针 */
// 调用 npyiter_resetbasepointers 重置嵌套迭代器的基础指针,如果失败返回 -1
if (npyiter_resetbasepointers(self) != NPY_SUCCEED) {
return -1;
}
// 返回成功标志
return 0;
}
static PyObject *
npyiter_has_delayed_bufalloc_get(
NewNpyArrayIterObject *self, void *NPY_UNUSED(ignored))
{
if (self->iter == NULL) {
// 如果迭代器为 NULL,设置错误信息并返回 NULL
PyErr_SetString(PyExc_ValueError,
"Iterator is invalid");
return NULL;
}
// 检查迭代器是否有延迟缓冲区分配,返回相应的 Python 布尔对象
if (NpyIter_HasDelayedBufAlloc(self->iter)) {
Py_RETURN_TRUE;
}
else {
Py_RETURN_FALSE;
}
}
static PyObject *
npyiter_iterationneedsapi_get(
NewNpyArrayIterObject *self, void *NPY_UNUSED(ignored))
{
if (self->iter == NULL) {
// 如果迭代器为 NULL,设置错误信息并返回 NULL
PyErr_SetString(PyExc_ValueError,
"Iterator is invalid");
return NULL;
}
// 检查迭代器是否需要 API 支持,返回相应的 Python 布尔对象
if (NpyIter_IterationNeedsAPI(self->iter)) {
Py_RETURN_TRUE;
}
else {
Py_RETURN_FALSE;
}
}
static PyObject *
npyiter_has_multi_index_get(
NewNpyArrayIterObject *self, void *NPY_UNUSED(ignored))
{
if (self->iter == NULL) {
// 如果迭代器为 NULL,设置错误信息并返回 NULL
PyErr_SetString(PyExc_ValueError,
"Iterator is invalid");
return NULL;
}
// 检查迭代器是否有多索引,返回相应的 Python 布尔对象
if (NpyIter_HasMultiIndex(self->iter)) {
Py_RETURN_TRUE;
}
else {
Py_RETURN_FALSE;
}
}
static PyObject *
npyiter_has_index_get(NewNpyArrayIterObject *self, void *NPY_UNUSED(ignored))
{
if (self->iter == NULL) {
// 如果迭代器为 NULL,设置错误信息并返回 NULL
PyErr_SetString(PyExc_ValueError,
"Iterator is invalid");
return NULL;
}
// 检查迭代器是否有索引,返回相应的 Python 布尔对象
if (NpyIter_HasIndex(self->iter)) {
Py_RETURN_TRUE;
}
else {
Py_RETURN_FALSE;
}
}
static PyObject *
npyiter_dtypes_get(NewNpyArrayIterObject *self, void *NPY_UNUSED(ignored))
{
PyObject *ret;
npy_intp iop, nop;
PyArray_Descr **dtypes;
if (self->iter == NULL) {
// 如果迭代器为 NULL,设置错误信息并返回 NULL
PyErr_SetString(PyExc_ValueError,
"Iterator is invalid");
return NULL;
}
// 获取迭代器的操作数和操作描述符数组
nop = NpyIter_GetNOp(self->iter);
dtypes = NpyIter_GetDescrArray(self->iter);
// 构造返回值,包含迭代器中所有操作的数据类型
ret = PyTuple_New(nop);
for (iop = 0; iop < nop; ++iop) {
PyTuple_SET_ITEM(ret, iop, PyArray_Descr_WRAP(dtypes[iop]));
}
// 返回包含操作数据类型的元组对象
return ret;
}
# 创建一个新的元组对象,元组长度为 nop
ret = PyTuple_New(nop);
# 检查元组对象是否创建成功,如果为 NULL,则返回 NULL
if (ret == NULL) {
return NULL;
}
# 获取 self 对象的 dtypes 属性
dtypes = self->dtypes;
# 遍历从 dtypes 中获取的数据类型数组
for (iop = 0; iop < nop; ++iop) {
# 获取当前索引 iop 处的数据类型对象指针
PyArray_Descr *dtype = dtypes[iop];
# 增加数据类型对象的引用计数,以防止在元组中被销毁
Py_INCREF(dtype);
# 将数据类型对象转换为 PyObject* 并设置为元组 ret 的第 iop 个元素
PyTuple_SET_ITEM(ret, iop, (PyObject *)dtype);
}
# 返回填充好的元组对象 ret
return ret;
static PyObject *
npyiter_ndim_get(NewNpyArrayIterObject *self, void *NPY_UNUSED(ignored))
{
// 检查迭代器是否为空
if (self->iter == NULL) {
// 如果迭代器为空,设置错误信息并返回空对象
PyErr_SetString(PyExc_ValueError,
"Iterator is invalid");
return NULL;
}
// 返回迭代器的维度作为一个 Python 长整型对象
return PyLong_FromLong(NpyIter_GetNDim(self->iter));
}
static PyObject *
npyiter_nop_get(NewNpyArrayIterObject *self, void *NPY_UNUSED(ignored))
{
// 检查迭代器是否为空
if (self->iter == NULL) {
// 如果迭代器为空,设置错误信息并返回空对象
PyErr_SetString(PyExc_ValueError,
"Iterator is invalid");
return NULL;
}
// 返回迭代器操作数的数量作为一个 Python 长整型对象
return PyLong_FromLong(NpyIter_GetNOp(self->iter));
}
static PyObject *
npyiter_itersize_get(NewNpyArrayIterObject *self, void *NPY_UNUSED(ignored))
{
// 检查迭代器是否为空
if (self->iter == NULL) {
// 如果迭代器为空,设置错误信息并返回空对象
PyErr_SetString(PyExc_ValueError,
"Iterator is invalid");
return NULL;
}
// 返回迭代器的迭代大小作为一个 Python 长整型对象
return PyLong_FromLong(NpyIter_GetIterSize(self->iter));
}
static PyObject *
npyiter_finished_get(NewNpyArrayIterObject *self, void *NPY_UNUSED(ignored))
{
// 检查迭代器是否为空或者是否已经完成迭代
if (self->iter == NULL || !self->finished) {
// 如果迭代器为空或者未完成迭代,返回 Python False 对象
Py_RETURN_FALSE;
}
else {
// 否则返回 Python True 对象
Py_RETURN_TRUE;
}
}
NPY_NO_EXPORT Py_ssize_t
npyiter_seq_length(NewNpyArrayIterObject *self)
{
// 检查迭代器是否为空
if (self->iter == NULL) {
// 如果迭代器为空,返回长度为 0
return 0;
}
else {
// 返回迭代器操作数的数量
return NpyIter_GetNOp(self->iter);
}
}
NPY_NO_EXPORT PyObject *
npyiter_seq_item(NewNpyArrayIterObject *self, Py_ssize_t i)
{
npy_intp ret_ndim;
npy_intp nop, innerloopsize, innerstride;
char *dataptr;
PyArray_Descr *dtype;
int has_external_loop;
Py_ssize_t i_orig = i;
// 检查迭代器是否为空或者是否已经完成迭代
if (self->iter == NULL || self->finished) {
// 如果迭代器为空或者已经完成迭代,设置错误信息并返回空对象
PyErr_SetString(PyExc_ValueError,
"Iterator is past the end");
return NULL;
}
// 检查是否有延迟的缓冲区分配
if (NpyIter_HasDelayedBufAlloc(self->iter)) {
// 如果有延迟的缓冲区分配,设置错误信息并返回空对象
PyErr_SetString(PyExc_ValueError,
"Iterator construction used delayed buffer allocation, "
"and no reset has been done yet");
return NULL;
}
nop = NpyIter_GetNOp(self->iter);
/* Negative indexing */
// 处理负索引
if (i < 0) {
i += nop;
}
// 检查索引是否超出范围
if (i < 0 || i >= nop) {
// 如果索引超出范围,设置错误信息并返回空对象
PyErr_Format(PyExc_IndexError,
"Iterator operand index %zd is out of bounds", i_orig);
return NULL;
}
#if 0
/*
* This check is disabled because it prevents things like
* np.add(it[0], it[1], it[2]), where it[2] is a write-only
* parameter. When write-only, the value of it[i] is
* likely random junk, as if it were allocated with an
* np.empty(...) call.
*/
// 这个检查被禁用,因为它阻止像 np.add(it[0], it[1], it[2]) 这样的操作,
// 其中 it[2] 是一个只写的参数。当只写时,it[i] 的值可能是随机垃圾,
// 就像它是通过 np.empty(...) 调用分配的一样。
#endif
// 获取数据指针和数据类型
dataptr = self->dataptrs[i];
dtype = self->dtypes[i];
has_external_loop = NpyIter_HasExternalLoop(self->iter);
// 如果有外部循环
if (has_external_loop) {
// 获取内部循环大小和内部步长,并设置返回维度为 1
innerloopsize = *self->innerloopsizeptr;
innerstride = self->innerstrides[i];
ret_ndim = 1;
}
else {
innerloopsize = 1;
innerstride = 0;
/* 如果迭代器遍历每个元素,则返回数组标量 */
ret_ndim = 0;
}
Py_INCREF(dtype);
/* 根据给定的描述符和基础数据创建一个新的数组对象 */
return PyArray_NewFromDescrAndBase(
&PyArray_Type, dtype,
ret_ndim, &innerloopsize, &innerstride, dataptr,
self->writeflags[i] ? NPY_ARRAY_WRITEABLE : 0,
NULL, (PyObject *)self);
// 返回一个 Python 对象,该对象代表从 self 迭代器中切片获取的子序列
NPY_NO_EXPORT PyObject *
npyiter_seq_slice(NewNpyArrayIterObject *self,
Py_ssize_t ilow, Py_ssize_t ihigh)
{
PyObject *ret; // 用于存储返回的 Python 元组对象
npy_intp nop; // 迭代器中操作数的数量
Py_ssize_t i; // 循环变量
// 如果迭代器为空或已经完成迭代,抛出 ValueError 异常
if (self->iter == NULL || self->finished) {
PyErr_SetString(PyExc_ValueError,
"Iterator is past the end");
return NULL;
}
// 如果迭代器使用了延迟的缓冲区分配,抛出 ValueError 异常
if (NpyIter_HasDelayedBufAlloc(self->iter)) {
PyErr_SetString(PyExc_ValueError,
"Iterator construction used delayed buffer allocation, "
"and no reset has been done yet");
return NULL;
}
nop = NpyIter_GetNOp(self->iter); // 获取迭代器操作数的数量
if (ilow < 0) {
ilow = 0; // 如果 ilow 小于 0,则将其设为 0
}
else if (ilow >= nop) {
ilow = nop-1; // 如果 ilow 大于或等于操作数的数量,将其设为 nop-1
}
if (ihigh < ilow) {
ihigh = ilow; // 如果 ihigh 小于 ilow,则将其设为 ilow
}
else if (ihigh > nop) {
ihigh = nop; // 如果 ihigh 大于操作数的数量,则将其设为 nop
}
// 创建一个元组对象 ret,长度为 ihigh-ilow
ret = PyTuple_New(ihigh-ilow);
if (ret == NULL) {
return NULL;
}
// 填充元组对象 ret,循环从 ilow 到 ihigh-1
for (i = ilow; i < ihigh ; ++i) {
// 调用 npyiter_seq_item 获取索引 i 对应的元素,并将其放入元组 ret 中
PyObject *item = npyiter_seq_item(self, i);
if (item == NULL) {
Py_DECREF(ret);
return NULL;
}
PyTuple_SET_ITEM(ret, i-ilow, item);
}
return ret; // 返回填充好的元组对象
}
// 设置 self 迭代器中索引 i 处的元素为 v
NPY_NO_EXPORT int
npyiter_seq_ass_item(NewNpyArrayIterObject *self, Py_ssize_t i, PyObject *v)
{
npy_intp nop, innerloopsize, innerstride; // 迭代器中操作数的数量,内部循环大小和步长
char *dataptr; // 指向数据的指针
PyArray_Descr *dtype; // 数组元素的描述符
PyArrayObject *tmp; // 临时数组对象
int ret, has_external_loop; // 返回值,是否有外部循环标志
Py_ssize_t i_orig = i; // 原始索引 i
// 如果 v 为 NULL,抛出 TypeError 异常,无法删除迭代器的元素
if (v == NULL) {
PyErr_SetString(PyExc_TypeError,
"Cannot delete iterator elements");
return -1;
}
// 如果迭代器为空或已经完成迭代,抛出 ValueError 异常
if (self->iter == NULL || self->finished) {
PyErr_SetString(PyExc_ValueError,
"Iterator is past the end");
return -1;
}
// 如果迭代器使用了延迟的缓冲区分配,抛出 ValueError 异常
if (NpyIter_HasDelayedBufAlloc(self->iter)) {
PyErr_SetString(PyExc_ValueError,
"Iterator construction used delayed buffer allocation, "
"and no reset has been done yet");
return -1;
}
nop = NpyIter_GetNOp(self->iter); // 获取迭代器操作数的数量
/* Negative indexing */
// 处理负索引
if (i < 0) {
i += nop;
}
// 检查索引 i 是否在有效范围内
if (i < 0 || i >= nop) {
PyErr_Format(PyExc_IndexError,
"Iterator operand index %zd is out of bounds", i_orig);
return -1;
}
// 检查索引 i 对应的操作数是否可写
if (!self->writeflags[i]) {
PyErr_Format(PyExc_RuntimeError,
"Iterator operand %zd is not writeable", i_orig);
return -1;
}
// 获取数据指针和数据类型描述符
dataptr = self->dataptrs[i];
dtype = self->dtypes[i];
// 检查是否有外部循环
has_external_loop = NpyIter_HasExternalLoop(self->iter);
// 如果有外部循环,设置内部循环大小和步长
if (has_external_loop) {
innerloopsize = *self->innerloopsizeptr;
innerstride = self->innerstrides[i];
}
else {
innerloopsize = 1;
innerstride = 0;
}
// 增加数据类型描述符的引用计数
Py_INCREF(dtype);
// 创建一个新的 NumPy 数组对象 tmp,使用给定的数据类型 dtype,
// 维度为 1,大小为 innerloopsize,步长为 innerstride,数据指针为 dataptr,
// 设置为可写模式 NPY_ARRAY_WRITEABLE,没有基础对象(NULL)。
tmp = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, dtype,
1, &innerloopsize,
&innerstride, dataptr,
NPY_ARRAY_WRITEABLE, NULL);
// 如果创建失败,返回 -1
if (tmp == NULL) {
return -1;
}
// 将数组对象 v 复制到 tmp 中,返回结果
ret = PyArray_CopyObject(tmp, v);
// 释放 tmp 的引用计数
Py_DECREF(tmp);
// 返回复制操作的结果
return ret;
static int
npyiter_seq_ass_slice(NewNpyArrayIterObject *self, Py_ssize_t ilow,
Py_ssize_t ihigh, PyObject *v)
{
npy_intp nop; // 定义变量nop,用于存储迭代器操作数的数量
Py_ssize_t i; // 定义变量i,用于迭代器操作
if (v == NULL) { // 如果传入的对象v为空
PyErr_SetString(PyExc_TypeError,
"Cannot delete iterator elements"); // 抛出类型错误异常,指明不能删除迭代器元素
return -1; // 返回-1表示操作失败
}
if (self->iter == NULL || self->finished) { // 如果迭代器指针为空或者迭代器已经完成
PyErr_SetString(PyExc_ValueError,
"Iterator is past the end"); // 抛出值错误异常,指明迭代器已经超出末尾
return -1; // 返回-1表示操作失败
}
if (NpyIter_HasDelayedBufAlloc(self->iter)) { // 如果迭代器构造过程使用了延迟缓冲区分配
PyErr_SetString(PyExc_ValueError,
"Iterator construction used delayed buffer allocation, "
"and no reset has been done yet"); // 抛出值错误异常,指明迭代器构造过程中使用了延迟缓冲区分配且尚未重置
return -1; // 返回-1表示操作失败
}
nop = NpyIter_GetNOp(self->iter); // 获取迭代器操作数的数量
if (ilow < 0) { // 如果传入的ilow小于0
ilow = 0; // 将ilow设为0
}
else if (ilow >= nop) { // 如果传入的ilow大于等于迭代器操作数的数量
ilow = nop-1; // 将ilow设为迭代器操作数的数量减1
}
if (ihigh < ilow) { // 如果传入的ihigh小于ilow
ihigh = ilow; // 将ihigh设为ilow
}
else if (ihigh > nop) { // 如果传入的ihigh大于迭代器操作数的数量
ihigh = nop; // 将ihigh设为迭代器操作数的数量
}
if (!PySequence_Check(v) || PySequence_Size(v) != ihigh-ilow) { // 如果v不是一个序列对象或者其大小不等于ihigh-ilow
PyErr_SetString(PyExc_ValueError,
"Wrong size to assign to iterator slice"); // 抛出值错误异常,指明分配给迭代器切片的大小不正确
return -1; // 返回-1表示操作失败
}
for (i = ilow; i < ihigh ; ++i) { // 循环遍历ilow到ihigh的范围
PyObject *item = PySequence_GetItem(v, i-ilow); // 获取v中索引为i-ilow的元素
if (item == NULL) { // 如果获取元素失败
return -1; // 返回-1表示操作失败
}
if (npyiter_seq_ass_item(self, i, item) < 0) { // 调用npyiter_seq_ass_item函数,将索引为i的迭代器位置赋值为item
Py_DECREF(item); // 减少item的引用计数
return -1; // 返回-1表示操作失败
}
Py_DECREF(item); // 减少item的引用计数
}
return 0; // 返回0表示操作成功
}
static PyObject *
npyiter_subscript(NewNpyArrayIterObject *self, PyObject *op)
{
if (self->iter == NULL || self->finished) { // 如果迭代器指针为空或者迭代器已经完成
PyErr_SetString(PyExc_ValueError,
"Iterator is past the end"); // 抛出值错误异常,指明迭代器已经超出末尾
return NULL; // 返回NULL表示操作失败
}
if (NpyIter_HasDelayedBufAlloc(self->iter)) { // 如果迭代器构造过程使用了延迟缓冲区分配
PyErr_SetString(PyExc_ValueError,
"Iterator construction used delayed buffer allocation, "
"and no reset has been done yet"); // 抛出值错误异常,指明迭代器构造过程中使用了延迟缓冲区分配且尚未重置
return NULL; // 返回NULL表示操作失败
}
if (PyLong_Check(op) || // 如果op是一个长整型对象或者
(PyIndex_Check(op) && !PySequence_Check(op))) { // op是一个索引对象但不是序列对象
npy_intp i = PyArray_PyIntAsIntp(op); // 将op转换为npy_intp类型的整数
if (error_converting(i)) { // 如果转换出错
return NULL; // 返回NULL表示操作失败
}
return npyiter_seq_item(self, i); // 返回调用npyiter_seq_item函数得到的结果
}
else if (PySlice_Check(op)) { // 如果op是一个切片对象
Py_ssize_t istart = 0, iend = 0, istep = 0, islicelength; // 定义几个变量用于存储切片的起始、结束、步长和切片长度
if (PySlice_GetIndicesEx(op, NpyIter_GetNOp(self->iter),
&istart, &iend, &istep, &islicelength) < 0) { // 调用PySlice_GetIndicesEx函数获取切片的索引范围
return NULL; // 返回NULL表示操作失败
}
if (istep != 1) { // 如果切片的步长不为1
PyErr_SetString(PyExc_ValueError,
"Iterator slicing only supports a step of 1"); // 抛出值错误异常,指明迭代器切片只支持步长为1
return NULL; // 返回NULL表示操作失败
}
return npyiter_seq_slice(self, istart, iend); // 返回调用npyiter_seq_slice函数得到的结果
}
PyErr_SetString(PyExc_TypeError,
"invalid index type for iterator indexing"); // 抛出类型错误异常,指明迭代器索引类型无效
return NULL; // 返回NULL表示操作失败
}
static int
npyiter_ass_subscript(NewNpyArrayIterObject *self, PyObject *op,
PyObject *value)
{
# 如果值为 NULL,则设置类型错误异常,指示无法删除迭代器元素
if (value == NULL) {
PyErr_SetString(PyExc_TypeError,
"Cannot delete iterator elements");
return -1;
}
# 如果迭代器为 NULL 或已经完成迭代,则设置值错误异常,指示迭代器已经超出末尾
if (self->iter == NULL || self->finished) {
PyErr_SetString(PyExc_ValueError,
"Iterator is past the end");
return -1;
}
# 如果迭代器使用了延迟的缓冲区分配,并且还没有进行重置,则设置值错误异常
if (NpyIter_HasDelayedBufAlloc(self->iter)) {
PyErr_SetString(PyExc_ValueError,
"Iterator construction used delayed buffer allocation, "
"and no reset has been done yet");
return -1;
}
# 如果操作对象是 PyLong 或者 PyIndex 但不是 PySequence,则尝试将操作对象转换为 npy_intp 类型,并进行序列赋值操作
if (PyLong_Check(op) ||
(PyIndex_Check(op) && !PySequence_Check(op))) {
npy_intp i = PyArray_PyIntAsIntp(op);
if (error_converting(i)) {
return -1;
}
return npyiter_seq_ass_item(self, i, value);
}
# 如果操作对象是 PySlice,则获取切片的起始、结束、步长和切片长度,并进行切片赋值操作
else if (PySlice_Check(op)) {
Py_ssize_t istart = 0, iend = 0, istep = 0, islicelength = 0;
if (PySlice_GetIndicesEx(op, NpyIter_GetNOp(self->iter),
&istart, &iend, &istep, &islicelength) < 0) {
return -1;
}
# 如果切片的步长不为 1,则设置值错误异常,因为迭代器切片赋值仅支持步长为 1
if (istep != 1) {
PyErr_SetString(PyExc_ValueError,
"Iterator slice assignment only supports a step of 1");
return -1;
}
return npyiter_seq_ass_slice(self, istart, iend, value);
}
# 如果操作对象不是合法的索引类型,则设置类型错误异常
PyErr_SetString(PyExc_TypeError,
"invalid index type for iterator indexing");
return -1;
{"reset",
(PyCFunction)npyiter_reset,
METH_NOARGS, NULL},
# 定义名为 "reset" 的方法,使用 npyiter_reset 函数实现,不接受参数,无额外信息
{"copy",
(PyCFunction)npyiter_copy,
METH_NOARGS, NULL},
# 定义名为 "copy" 的方法,使用 npyiter_copy 函数实现,不接受参数,无额外信息
{"__copy__",
(PyCFunction)npyiter_copy,
METH_NOARGS, NULL},
# 定义名为 "__copy__" 的方法,使用 npyiter_copy 函数实现,不接受参数,无额外信息
{"iternext",
(PyCFunction)npyiter_iternext,
METH_NOARGS, NULL},
# 定义名为 "iternext" 的方法,使用 npyiter_iternext 函数实现,不接受参数,无额外信息
{"remove_axis",
(PyCFunction)npyiter_remove_axis,
METH_VARARGS, NULL},
# 定义名为 "remove_axis" 的方法,使用 npyiter_remove_axis 函数实现,接受可变参数,无额外信息
{"remove_multi_index",
(PyCFunction)npyiter_remove_multi_index,
METH_NOARGS, NULL},
# 定义名为 "remove_multi_index" 的方法,使用 npyiter_remove_multi_index 函数实现,不接受参数,无额外信息
{"enable_external_loop",
(PyCFunction)npyiter_enable_external_loop,
METH_NOARGS, NULL},
# 定义名为 "enable_external_loop" 的方法,使用 npyiter_enable_external_loop 函数实现,不接受参数,无额外信息
{"debug_print",
(PyCFunction)npyiter_debug_print,
METH_NOARGS, NULL},
# 定义名为 "debug_print" 的方法,使用 npyiter_debug_print 函数实现,不接受参数,无额外信息
{"__enter__", (PyCFunction)npyiter_enter,
METH_NOARGS, NULL},
# 定义名为 "__enter__" 的方法,使用 npyiter_enter 函数实现,不接受参数,无额外信息
{"__exit__", (PyCFunction)npyiter_exit,
METH_VARARGS, NULL},
# 定义名为 "__exit__" 的方法,使用 npyiter_exit 函数实现,接受可变参数,无额外信息
{"close", (PyCFunction)npyiter_close,
METH_NOARGS, NULL},
# 定义名为 "close" 的方法,使用 npyiter_close 函数实现,不接受参数,无额外信息
{NULL, NULL, 0, NULL},
# 结束方法定义的标志
{"has_multi_index",
// 用于获取是否具有多重索引的属性,对应的 getter 函数为 npyiter_has_multi_index_get
(getter)npyiter_has_multi_index_get,
// 没有 setter 函数,因此为 NULL
NULL,
// 删除时的函数,这里为 NULL
NULL,
// 文档字符串,这里为 NULL
NULL},
{"has_index",
// 用于获取是否具有索引的属性,对应的 getter 函数为 npyiter_has_index_get
(getter)npyiter_has_index_get,
NULL, NULL, NULL},
{"dtypes",
// 用于获取迭代器数据类型的属性,对应的 getter 函数为 npyiter_dtypes_get
(getter)npyiter_dtypes_get,
NULL, NULL, NULL},
{"ndim",
// 用于获取迭代器维度的属性,对应的 getter 函数为 npyiter_ndim_get
(getter)npyiter_ndim_get,
NULL, NULL, NULL},
{"nop",
// 用于获取 nop 的属性,对应的 getter 函数为 npyiter_nop_get
(getter)npyiter_nop_get,
NULL, NULL, NULL},
{"itersize",
// 用于获取迭代器尺寸的属性,对应的 getter 函数为 npyiter_itersize_get
(getter)npyiter_itersize_get,
NULL, NULL, NULL},
{"finished",
// 用于获取迭代器是否完成的属性,对应的 getter 函数为 npyiter_finished_get
(getter)npyiter_finished_get,
NULL, NULL, NULL},
{NULL, NULL, NULL, NULL, NULL}
# 定义结构体 PySequenceMethods,并初始化其成员
NPY_NO_EXPORT PySequenceMethods npyiter_as_sequence = {
(lenfunc)npyiter_seq_length, /*sq_length*/ # 设置序列长度函数指针
(binaryfunc)NULL, /*sq_concat*/ # 没有定义序列连接操作,置为 NULL
(ssizeargfunc)NULL, /*sq_repeat*/ # 没有定义序列重复操作,置为 NULL
(ssizeargfunc)npyiter_seq_item, /*sq_item*/ # 设置获取序列元素的函数指针
(ssizessizeargfunc)NULL, /*sq_slice*/ # 没有定义序列切片操作,置为 NULL
(ssizeobjargproc)npyiter_seq_ass_item, /*sq_ass_item*/ # 设置设置序列元素的函数指针
(ssizessizeobjargproc)NULL, /*sq_ass_slice*/ # 没有定义序列切片设置操作,置为 NULL
(objobjproc)NULL, /*sq_contains */ # 没有定义序列包含操作,置为 NULL
(binaryfunc)NULL, /*sq_inplace_concat */ # 没有定义序列原地连接操作,置为 NULL
(ssizeargfunc)NULL, /*sq_inplace_repeat */ # 没有定义序列原地重复操作,置为 NULL
};
# 定义结构体 PyMappingMethods,并初始化其成员
NPY_NO_EXPORT PyMappingMethods npyiter_as_mapping = {
(lenfunc)npyiter_seq_length, /*mp_length*/ # 设置映射长度函数指针
(binaryfunc)npyiter_subscript, /*mp_subscript*/ # 设置映射获取元素的函数指针
(objobjargproc)npyiter_ass_subscript, /*mp_ass_subscript*/ # 设置映射设置元素的函数指针
};
# 定义结构体 PyTypeObject,并初始化其成员
NPY_NO_EXPORT PyTypeObject NpyIter_Type = {
PyVarObject_HEAD_INIT(NULL, 0) # 初始化基类对象
.tp_name = "numpy.nditer", # 设置类型对象的名称
.tp_basicsize = sizeof(NewNpyArrayIterObject), # 设置类型对象的基本大小
.tp_dealloc = (destructor)npyiter_dealloc, # 设置析构函数指针
.tp_as_sequence = &npyiter_as_sequence, # 设置序列操作方法集合
.tp_as_mapping = &npyiter_as_mapping, # 设置映射操作方法集合
.tp_flags = Py_TPFLAGS_DEFAULT, # 设置类型对象的标志
.tp_iternext = (iternextfunc)npyiter_next, # 设置迭代器的下一个函数指针
.tp_methods = npyiter_methods, # 设置类型对象的方法集合
.tp_members = npyiter_members, # 设置类型对象的成员变量集合
.tp_getset = npyiter_getsets, # 设置类型对象的属性访问器集合
.tp_init = (initproc)npyiter_init, # 设置初始化函数指针
.tp_new = npyiter_new, # 设置新建对象函数指针
};
.\numpy\numpy\_core\src\multiarray\nditer_pywrap.h
// 如果未定义 NUMPY_CORE_SRC_MULTIARRAY_NDITER_PYWRAP_H_ 宏,则开始条件编译保护
// 声明一个不导出的函数 NpyIter_NestedIters,接受三个 PyObject 类型的参数
// 第一个参数 self 没有使用,参数 args 和 kwds 分别表示位置参数和关键字参数
NPY_NO_EXPORT PyObject *
NpyIter_NestedIters(PyObject *NPY_UNUSED(self),
PyObject *args, PyObject *kwds);
// 结束条件编译保护,确保只有在未定义 NUMPY_CORE_SRC_MULTIARRAY_NDITER_PYWRAP_H_ 宏时才会包含上述内容
.\numpy\numpy\_core\src\multiarray\npy_buffer.h
// 声明了一个名为 array_as_buffer 的外部变量,类型为 PyBufferProcs 结构体
extern NPY_NO_EXPORT PyBufferProcs array_as_buffer;
// 声明了一个非导出函数 _buffer_info_free,接受一个 void 指针和一个 PyObject 指针作为参数,返回一个整型值
NPY_NO_EXPORT int
_buffer_info_free(void *buffer_info, PyObject *obj);
// 声明了一个非导出函数 _descriptor_from_pep3118_format,接受一个 const char* 参数,返回一个 PyArray_Descr* 指针
NPY_NO_EXPORT PyArray_Descr*
_descriptor_from_pep3118_format(char const *s);
// 声明了一个非导出函数 void_getbuffer,接受一个 PyObject 指针和一个 Py_buffer 指针以及一个整型标志 flags 作为参数,返回一个整型值
NPY_NO_EXPORT int
void_getbuffer(PyObject *obj, Py_buffer *view, int flags);
.\numpy\numpy\_core\src\multiarray\npy_static_data.c
/* numpy static data structs and initialization */
/* Define NPY_NO_DEPRECATED_API to ensure we use the latest API version */
/* Define _UMATHMODULE and _MULTIARRAYMODULE to include corresponding modules */
/* Ensure PY_SSIZE_T_CLEAN is defined to use the new ssize_t API */
/* Include Python.h to access Python/C API */
/* Include structmember.h for Python object structure handling */
/* Include numpy C API headers */
/* Definition of static variables */
/* NPY_VISIBILITY_HIDDEN indicates these are not exposed externally */
NPY_VISIBILITY_HIDDEN npy_interned_str_struct npy_interned_str;
NPY_VISIBILITY_HIDDEN npy_static_pydata_struct npy_static_pydata;
NPY_VISIBILITY_HIDDEN npy_static_cdata_struct npy_static_cdata;
/* Macro to intern a string into a Python Unicode object and assign to a struct member */
/* Assertion to ensure the struct member is initially NULL */ \
assert(npy_interned_str.struct_member == NULL); \
/* Intern the string literal into a Python Unicode object */ \
npy_interned_str.struct_member = PyUnicode_InternFromString(string); \
/* Check if the intern operation succeeded */ \
if (npy_interned_str.struct_member == NULL) { \
return -1; \
} \
/* Function to intern a list of predefined strings */
NPY_NO_EXPORT int
intern_strings(void)
{
/* Macro calls to intern each string into corresponding struct members */
INTERN_STRING(current_allocator, "current_allocator");
INTERN_STRING(array, "__array__");
INTERN_STRING(array_function, "__array_function__");
INTERN_STRING(array_struct, "__array_struct__");
INTERN_STRING(array_priority, "__array_priority__");
INTERN_STRING(array_interface, "__array_interface__");
INTERN_STRING(array_ufunc, "__array_ufunc__");
INTERN_STRING(array_wrap, "__array_wrap__");
INTERN_STRING(array_finalize, "__array_finalize__");
INTERN_STRING(implementation, "_implementation");
INTERN_STRING(axis1, "axis1");
INTERN_STRING(axis2, "axis2");
INTERN_STRING(like, "like");
INTERN_STRING(numpy, "numpy");
INTERN_STRING(where, "where");
INTERN_STRING(convert, "convert");
INTERN_STRING(preserve, "preserve");
INTERN_STRING(convert_if_no_array, "convert_if_no_array");
INTERN_STRING(cpu, "cpu");
INTERN_STRING(dtype, "dtype");
INTERN_STRING(
array_err_msg_substr,
"__array__() got an unexpected keyword argument 'copy'");
INTERN_STRING(out, "out");
INTERN_STRING(errmode_strings[0], "ignore");
INTERN_STRING(errmode_strings[1], "warn");
INTERN_STRING(errmode_strings[2], "raise");
INTERN_STRING(errmode_strings[3], "call");
INTERN_STRING(errmode_strings[4], "print");
INTERN_STRING(errmode_strings[5], "log");
INTERN_STRING(__dlpack__, "__dlpack__");
INTERN_STRING(pyvals_name, "UFUNC_PYVALS_NAME");
/* Return success */
return 0;
}
/* Macro to import a global object from a module and assert its existence */
/* Assertion to ensure the object is initially NULL */ \
assert(object == NULL); \
/* Attempt to import the object from the module using npy_cache_import */ \
npy_cache_import(base_path, name, &object); \
/* Check if the import succeeded */ \
if (object == NULL) { \
return -1; \
}
/*
* Initializes global constants.
*
* All global constants should live inside the npy_static_pydata
* struct.
*
* Not all entries in the struct are initialized here, some are
* initialized later but care must be taken in those cases to initialize
* the constant in a thread-safe manner, ensuring it is initialized
* exactly once.
*
* Anything initialized here is initialized during module import which
* the python interpreter ensures is done in a single thread.
*
* Anything imported here should not need the C-layer at all and will be
* imported before anything on the C-side is initialized.
*/
NPY_NO_EXPORT int
initialize_static_globals(void)
{
/*
* Initialize contents of npy_static_pydata struct
*
* This struct holds cached references to python objects
* that we want to keep alive for the lifetime of the
* module for performance reasons
*/
// 导入全局变量 "math" 模块中的 "floor" 函数,并存储在 npy_static_pydata.math_floor_func 中
IMPORT_GLOBAL("math", "floor",
npy_static_pydata.math_floor_func);
// 导入全局变量 "math" 模块中的 "ceil" 函数,并存储在 npy_static_pydata.math_ceil_func 中
IMPORT_GLOBAL("math", "ceil",
npy_static_pydata.math_ceil_func);
// 导入全局变量 "math" 模块中的 "trunc" 函数,并存储在 npy_static_pydata.math_trunc_func 中
IMPORT_GLOBAL("math", "trunc",
npy_static_pydata.math_trunc_func);
// 导入全局变量 "math" 模块中的 "gcd" 函数,并存储在 npy_static_pydata.math_gcd_func 中
IMPORT_GLOBAL("math", "gcd",
npy_static_pydata.math_gcd_func);
// 导入全局变量 "numpy.exceptions" 模块中的 "AxisError" 异常,并存储在 npy_static_pydata.AxisError 中
IMPORT_GLOBAL("numpy.exceptions", "AxisError",
npy_static_pydata.AxisError);
// 导入全局变量 "numpy.exceptions" 模块中的 "ComplexWarning" 异常,并存储在 npy_static_pydata.ComplexWarning 中
IMPORT_GLOBAL("numpy.exceptions", "ComplexWarning",
npy_static_pydata.ComplexWarning);
// 导入全局变量 "numpy.exceptions" 模块中的 "DTypePromotionError" 异常,并存储在 npy_static_pydata.DTypePromotionError 中
IMPORT_GLOBAL("numpy.exceptions", "DTypePromotionError",
npy_static_pydata.DTypePromotionError);
// 导入全局变量 "numpy.exceptions" 模块中的 "TooHardError" 异常,并存储在 npy_static_pydata.TooHardError 中
IMPORT_GLOBAL("numpy.exceptions", "TooHardError",
npy_static_pydata.TooHardError);
// 导入全局变量 "numpy.exceptions" 模块中的 "VisibleDeprecationWarning" 异常,并存储在 npy_static_pydata.VisibleDeprecationWarning 中
IMPORT_GLOBAL("numpy.exceptions", "VisibleDeprecationWarning",
npy_static_pydata.VisibleDeprecationWarning);
// 导入全局变量 "numpy._globals" 模块中的 "_CopyMode" 对象,并存储在 npy_static_pydata._CopyMode 中
IMPORT_GLOBAL("numpy._globals", "_CopyMode",
npy_static_pydata._CopyMode);
// 导入全局变量 "numpy._globals" 模块中的 "_NoValue" 对象,并存储在 npy_static_pydata._NoValue 中
IMPORT_GLOBAL("numpy._globals", "_NoValue",
npy_static_pydata._NoValue);
// 导入全局变量 "numpy._core._exceptions" 模块中的 "_ArrayMemoryError" 异常,并存储在 npy_static_pydata._ArrayMemoryError 中
IMPORT_GLOBAL("numpy._core._exceptions", "_ArrayMemoryError",
npy_static_pydata._ArrayMemoryError);
// 导入全局变量 "numpy._core._exceptions" 模块中的 "_UFuncBinaryResolutionError" 异常,并存储在 npy_static_pydata._UFuncBinaryResolutionError 中
IMPORT_GLOBAL("numpy._core._exceptions", "_UFuncBinaryResolutionError",
npy_static_pydata._UFuncBinaryResolutionError);
// 导入全局变量 "numpy._core._exceptions" 模块中的 "_UFuncInputCastingError" 异常,并存储在 npy_static_pydata._UFuncInputCastingError 中
IMPORT_GLOBAL("numpy._core._exceptions", "_UFuncInputCastingError",
npy_static_pydata._UFuncInputCastingError);
// 导入全局变量 "numpy._core._exceptions" 模块中的 "_UFuncNoLoopError" 异常,并存储在 npy_static_pydata._UFuncNoLoopError 中
IMPORT_GLOBAL("numpy._core._exceptions", "_UFuncNoLoopError",
npy_static_pydata._UFuncNoLoopError);
// 导入全局变量 "numpy._core._exceptions" 模块中的 "_UFuncOutputCastingError" 异常,并存储在 npy_static_pydata._UFuncOutputCastingError 中
IMPORT_GLOBAL("numpy._core._exceptions", "_UFuncOutputCastingError",
npy_static_pydata._UFuncOutputCastingError);
// 导入全局变量 "os" 模块中的 "fspath" 函数,并存储在 npy_static_pydata.os_fspath 中
IMPORT_GLOBAL("os", "fspath",
npy_static_pydata.os_fspath);
// 导入全局变量 "os" 模块中的 "PathLike" 对象,并存储在 npy_static_pydata.os_PathLike 中
IMPORT_GLOBAL("os", "PathLike",
npy_static_pydata.os_PathLike);
// 创建 PyArray_Descr 结构,用于表示 NPY_DOUBLE 类型的数组描述符,赋值给 tmp 变量
PyArray_Descr *tmp = PyArray_DescrFromType(NPY_DOUBLE);
npy_static_pydata.default_truediv_type_tup =
PyTuple_Pack(3, tmp, tmp, tmp);
// 创建一个包含三个相同对象 tmp 的元组,并赋值给全局变量 default_truediv_type_tup
Py_DECREF(tmp);
// 减少 tmp 的引用计数,防止内存泄漏
if (npy_static_pydata.default_truediv_type_tup == NULL) {
return -1;
}
// 检查元组创建是否成功,若失败则返回 -1
npy_static_pydata.kwnames_is_copy = Py_BuildValue("(s)", "copy");
// 创建一个包含字符串 "copy" 的元组,并赋值给全局变量 kwnames_is_copy
if (npy_static_pydata.kwnames_is_copy == NULL) {
return -1;
}
// 检查元组创建是否成功,若失败则返回 -1
npy_static_pydata.one_obj = PyLong_FromLong((long) 1);
// 创建一个包含整数 1 的 PyLong 对象,并赋值给全局变量 one_obj
if (npy_static_pydata.one_obj == NULL) {
return -1;
}
// 检查对象创建是否成功,若失败则返回 -1
npy_static_pydata.zero_obj = PyLong_FromLong((long) 0);
// 创建一个包含整数 0 的 PyLong 对象,并赋值给全局变量 zero_obj
if (npy_static_pydata.zero_obj == NULL) {
return -1;
}
// 检查对象创建是否成功,若失败则返回 -1
/*
* Initialize contents of npy_static_cdata struct
*
* Note that some entries are initialized elsewhere. Care
* must be taken to ensure all entries are initialized during
* module initialization and immutable thereafter.
*
* This struct holds global static caches. These are set
* up this way for performance reasons.
*/
PyObject *flags = PySys_GetObject("flags"); /* borrowed object */
// 获取名为 "flags" 的系统模块对象,并赋值给 flags(借用引用)
if (flags == NULL) {
PyErr_SetString(PyExc_AttributeError, "cannot get sys.flags");
return -1;
}
// 检查获取是否成功,若失败则设置异常并返回 -1
PyObject *level = PyObject_GetAttrString(flags, "optimize");
// 获取 flags 对象的名为 "optimize" 的属性,并赋值给 level
if (level == NULL) {
return -1;
}
// 检查获取是否成功,若失败则返回 -1
npy_static_cdata.optimize = PyLong_AsLong(level);
// 将 level 转换为长整型并赋值给全局变量 optimize
Py_DECREF(level);
// 减少 level 的引用计数,防止内存泄漏
/*
* see unpack_bits for how this table is used.
*
* LUT for bigendian bitorder, littleendian is handled via
* byteswapping in the loop.
*
* 256 8 byte blocks representing 8 bits expanded to 1 or 0 bytes
*/
npy_intp j;
// 循环变量 j 的声明
for (j=0; j < 256; j++) {
npy_intp k;
// 循环变量 k 的声明
for (k=0; k < 8; k++) {
npy_uint8 v = (j & (1 << k)) == (1 << k);
// 计算当前位的值(0或1),并赋值给 v
npy_static_cdata.unpack_lookup_big[j].bytes[7 - k] = v;
// 将 v 存储在 unpack_lookup_big[j] 的相应位置
}
}
return 0;
// 函数正常执行完毕,返回 0 表示成功
/*
* Verifies all entries in npy_interned_str and npy_static_pydata are
* non-NULL.
*
* Called at the end of initialization for _multiarray_umath. Some
* entries are initialized outside of this file because they depend on
* items that are initialized late in module initialization but they
* should all be initialized by the time this function is called.
*/
NPY_NO_EXPORT int
verify_static_structs_initialized(void) {
// verify all entries in npy_interned_str are filled in
for (int i=0; i < (sizeof(npy_interned_str_struct)/sizeof(PyObject *)); i++) {
// Check if the i-th entry in npy_interned_str is NULL
if (*(((PyObject **)&npy_interned_str) + i) == NULL) {
// Raise a SystemError if a NULL entry is found
PyErr_Format(
PyExc_SystemError,
"NumPy internal error: NULL entry detected in "
"npy_interned_str at index %d", i);
// Return -1 indicating error
return -1;
}
}
// verify all entries in npy_static_pydata are filled in
for (int i=0; i < (sizeof(npy_static_pydata_struct)/sizeof(PyObject *)); i++) {
// Check if the i-th entry in npy_static_pydata is NULL
if (*(((PyObject **)&npy_static_pydata) + i) == NULL) {
// Raise a SystemError if a NULL entry is found
PyErr_Format(
PyExc_SystemError,
"NumPy internal error: NULL entry detected in "
"npy_static_pydata at index %d", i);
// Return -1 indicating error
return -1;
}
}
// All entries are initialized correctly, return 0 indicating success
return 0;
}
.\numpy\numpy\_core\src\multiarray\npy_static_data.h
// 定义了头文件的宏保护,防止多重包含
NPY_NO_EXPORT int
initialize_static_globals(void);
// 声明了初始化静态全局变量的函数
NPY_NO_EXPORT int
intern_strings(void);
// 声明了内部字符串初始化函数
NPY_NO_EXPORT int
verify_static_structs_initialized(void);
// 声明了验证静态结构体是否初始化完成的函数
typedef struct npy_interned_str_struct {
// 定义了结构体 npy_interned_str_struct,用于存储内部字符串对象
PyObject *current_allocator; // 当前分配器
PyObject *array; // 数组
PyObject *array_function; // 数组函数
PyObject *array_struct; // 数组结构
PyObject *array_priority; // 数组优先级
PyObject *array_interface; // 数组接口
PyObject *array_wrap; // 数组包装
PyObject *array_finalize; // 数组终结器
PyObject *array_ufunc; // 数组 ufunc
PyObject *implementation; // 实现
PyObject *axis1; // 轴1
PyObject *axis2; // 轴2
PyObject *like; // 类似
PyObject *numpy; // NumPy
PyObject *where; // where 函数
PyObject *convert; // 转换
PyObject *preserve; // 保持
PyObject *convert_if_no_array; // 如果无数组则转换
PyObject *cpu; // CPU
PyObject *dtype; // 数据类型
PyObject *array_err_msg_substr; // 数组错误消息子字符串
PyObject *out; // 输出
PyObject *errmode_strings[6]; // 错误模式字符串数组
PyObject *__dlpack__; // __dlpack__ 对象
PyObject *pyvals_name; // Python 值名称
} npy_interned_str_struct;
/*
* A struct that stores static global data used throughout
* _multiarray_umath, mostly to cache results that would be
* prohibitively expensive to compute at runtime in a tight loop.
*
* All items in this struct should be initialized during module
* initialization and thereafter should be immutable. Mutating items in
* this struct after module initialization is likely not thread-safe.
*/
// 定义了一个结构体 npy_static_pydata_struct,用于存储在 _multiarray_umath 中使用的静态全局数据
typedef struct npy_static_pydata_struct {
/*
* Used in ufunc_type_resolution.c to avoid reconstructing a tuple
* storing the default true division return types.
*/
PyObject *default_truediv_type_tup; // 用于存储默认真除法返回类型的元组,避免重复构建
/*
* Used to set up the default extobj context variable
*/
PyObject *default_extobj_capsule; // 用于设置默认的 extobj 上下文变量
/*
* The global ContextVar to store the extobject. It is exposed to Python
* as `_extobj_contextvar`.
*/
PyObject *npy_extobj_contextvar; // 用于存储 extobject 的全局 ContextVar,作为 `_extobj_contextvar` 暴露给 Python 使用
/*
* A reference to ndarray's implementations for __array_*__ special methods
*/
PyObject *ndarray_array_ufunc; // ndarray 的实现,用于 __array_*__ 特殊方法
PyObject *ndarray_array_finalize; // ndarray 的 array_finalize 方法
PyObject *ndarray_array_function; // ndarray 的 array_function 方法
/*
* References to the '1' and '0' PyLong objects
*/
PyObject *one_obj; // '1' 的 PyLong 对象引用
PyObject *zero_obj; // '0' 的 PyLong 对象引用
/*
* Reference to an np.array(0, dtype=np.long) instance
*/
PyObject *zero_pyint_like_arr; // np.array(0, dtype=np.long) 实例的引用
/*
* References to items obtained via an import at module initialization
*/
PyObject *AxisError; // AxisError 对象引用
PyObject *ComplexWarning; // ComplexWarning 对象引用
PyObject *DTypePromotionError; // DTypePromotionError 对象引用
PyObject *TooHardError; // TooHardError 对象引用
PyObject *VisibleDeprecationWarning; // VisibleDeprecationWarning 对象引用
PyObject *_CopyMode; // _CopyMode 对象引用
PyObject *_NoValue; // _NoValue 对象引用
PyObject *_ArrayMemoryError; // _ArrayMemoryError 对象引用
PyObject *_UFuncBinaryResolutionError; // _UFuncBinaryResolutionError 对象引用
PyObject *_UFuncInputCastingError; // _UFuncInputCastingError 对象引用
PyObject *_UFuncNoLoopError; // _UFuncNoLoopError 对象引用
PyObject *_UFuncOutputCastingError; // _UFuncOutputCastingError 对象引用
PyObject *math_floor_func; // math_floor_func 函数引用
PyObject *math_ceil_func; // math_ceil_func 函数引用
PyObject *math_trunc_func; // math_trunc_func 函数引用
PyObject *math_gcd_func; // math_gcd_func 函数引用
PyObject *os_PathLike; // os_PathLike 对象引用
PyObject *os_fspath; // os_fspath 对象引用
/*
* 在 __array__ 的内部使用,避免在内联构建元组
*/
PyObject *kwnames_is_copy;
/*
* 在 __imatmul__ 中使用,避免在内联构建元组
*/
PyObject *axes_1d_obj_kwargs;
PyObject *axes_2d_obj_kwargs;
/*
* 用于 CPU 特性检测和调度
*/
PyObject *cpu_dispatch_registry;
/*
* 引用了缓存的 ArrayMethod 实现,避免重复创建它们
*/
PyObject *VoidToGenericMethod;
PyObject *GenericToVoidMethod;
PyObject *ObjectToGenericMethod;
PyObject *GenericToObjectMethod;
/*
* 结构体定义:npy_static_pydata_struct,用于存储静态的 Python 数据结构
*/
typedef struct npy_static_pydata_struct {
/*
* 存储 sys.flags.optimize 的长整型值,用于在 add_docstring 实现中使用
*/
long optimize;
/*
* 用于 unpack_bits 的查找表
*/
union {
npy_uint8 bytes[8];
npy_uint64 uint64;
} unpack_lookup_big[256];
/*
* 从类型字符中恢复整数类型编号的查找表。
*
* 参见 arraytypes.c.src 中的 _MAX_LETTER 和 LETTER_TO_NUM 宏。
*
* 最小的类型编号是 '?',最大的受到 'z' 限制。
*
* 这与内置的 dtypes 同时初始化。
*/
npy_int16 _letter_to_num['z' + 1 - '?'];
} npy_static_cdata_struct;
/*
* NPY_VISIBILITY_HIDDEN:用于声明不对外部可见的符号
* 声明一个对外部不可见的字符串结构 npy_interned_str
*/
NPY_VISIBILITY_HIDDEN extern npy_interned_str_struct npy_interned_str;
/*
* NPY_VISIBILITY_HIDDEN:用于声明不对外部可见的符号
* 声明一个对外部不可见的静态 Python 数据结构 npy_static_pydata
*/
NPY_VISIBILITY_HIDDEN extern npy_static_pydata_struct npy_static_pydata;
/*
* NPY_VISIBILITY_HIDDEN:用于声明不对外部可见的符号
* 声明一个对外部不可见的静态 C 数据结构 npy_static_cdata
*/
NPY_VISIBILITY_HIDDEN extern npy_static_cdata_struct npy_static_cdata;
#endif // NUMPY_CORE_SRC_MULTIARRAY_STATIC_DATA_H_
.\numpy\numpy\_core\src\multiarray\number.c
/*
* 定义宏,确保使用的 NumPy API 版本没有废弃的部分
*/
/*
* 定义宏,标识 _MULTIARRAYMODULE
*/
/*
* 清除 PY_SSIZE_T 的旧定义,确保使用最新版本的类型定义
*/
/*
* 包含 Python 核心头文件
*/
/*
* 包含结构成员头文件,用于定义结构体成员
*/
/*
* 包含 NumPy 的数组对象头文件
*/
/*
* 包含 NumPy 配置文件
*/
/*
* 包含 NumPy 的 Python 兼容性功能
*/
/*
* 包含 NumPy 的导入功能
*/
/*
* 包含 NumPy 的公共功能
*/
/*
* 包含 NumPy 的数值操作
*/
/*
* 包含 NumPy 的临时省略功能
*/
/*
* 包含 NumPy 的二元操作重载
*/
/*
* 包含 NumPy 的通用函数操作重载
*/
/*
* 包含 NumPy 的抽象数据类型功能
*/
/*
* 包含 NumPy 的数据类型转换功能
*/
/*************************************************************************
**************** 实现数字协议 ****************************
*************************************************************************/
/*
* 这个全局变量不在全局数据结构中,避免在 multiarraymodule.h 中需要包含 NumericOps 结构的定义
* 在模块初始化期间以线程安全的方式填充
*/
NPY_NO_EXPORT NumericOps n_ops; /* 注意:静态对象被初始化为零 */
/*
* 函数的前向声明,可能会重新安排函数而不是将其移动
*/
static PyObject *
array_inplace_add(PyArrayObject *m1, PyObject *m2);
static PyObject *
array_inplace_subtract(PyArrayObject *m1, PyObject *m2);
static PyObject *
array_inplace_multiply(PyArrayObject *m1, PyObject *m2);
static PyObject *
array_inplace_true_divide(PyArrayObject *m1, PyObject *m2);
static PyObject *
array_inplace_floor_divide(PyArrayObject *m1, PyObject *m2);
static PyObject *
array_inplace_bitwise_and(PyArrayObject *m1, PyObject *m2);
static PyObject *
array_inplace_bitwise_or(PyArrayObject *m1, PyObject *m2);
static PyObject *
array_inplace_bitwise_xor(PyArrayObject *m1, PyObject *m2);
static PyObject *
array_inplace_left_shift(PyArrayObject *m1, PyObject *m2);
static PyObject *
array_inplace_right_shift(PyArrayObject *m1, PyObject *m2);
static PyObject *
array_inplace_remainder(PyArrayObject *m1, PyObject *m2);
static PyObject *
array_inplace_power(PyArrayObject *a1, PyObject *o2, PyObject *NPY_UNUSED(modulo));
static PyObject *
array_inplace_matrix_multiply(PyArrayObject *m1, PyObject *m2);
/*
* 字典可以包含任何数值操作,按名称存储
* 不包含在字典中的操作将不会被更改
*/
/* FIXME - 宏包含返回值 */
res = PyDict_GetItemStringRef(dict,
if (res == -1) { \
return -1; \
} \
else if (res == 1) { \
if (!(PyCallable_Check(temp))) { \
Py_DECREF(temp); \
return -1; \
} \
Py_XSETREF(n_ops.op, temp); \
}
/*
* 设置数值操作函数的实现
*/
NPY_NO_EXPORT int
_PyArray_SetNumericOps(PyObject *dict)
{
PyObject *temp = NULL;
int res;
/*
* 设置每种数值操作函数,通过从字典中获取并检查其有效性,然后进行设置
*/
SET(add);
SET(subtract);
SET(multiply);
SET(divide);
SET(remainder);
SET(divmod);
SET(power);
SET(square);
SET(reciprocal);
SET(_ones_like);
SET(sqrt);
SET(cbrt);
SET(negative);
SET(positive);
SET(absolute);
SET(invert);
SET(left_shift);
SET(right_shift);
SET(bitwise_and);
SET(bitwise_or);
SET(bitwise_xor);
return 0;
}
注释结束。
SET(less);
SET(less_equal);
SET(equal);
SET(not_equal);
SET(greater);
SET(greater_equal);
SET(floor_divide);
SET(true_divide);
SET(logical_or);
SET(logical_and);
SET(floor);
SET(ceil);
SET(maximum);
SET(minimum);
SET(rint);
SET(conjugate);
SET(matmul);
SET(clip);
npy_static_pydata.axes_1d_obj_kwargs = Py_BuildValue(
"{s, [(i), (i, i), (i)]}", "axes", -1, -2, -1, -1);
if (npy_static_pydata.axes_1d_obj_kwargs == NULL) {
return -1;
}
npy_static_pydata.axes_2d_obj_kwargs = Py_BuildValue(
"{s, [(i, i), (i, i), (i, i)]}", "axes", -2, -1, -2, -1, -2, -1);
if (npy_static_pydata.axes_2d_obj_kwargs == NULL) {
return -1;
}
return 0;
static PyObject *
_get_keywords(int rtype, PyArrayObject *out)
{
PyObject *kwds = NULL;
// 如果数据类型不是 NPY_NOTYPE 或者输出对象不为空
if (rtype != NPY_NOTYPE || out != NULL) {
// 创建一个空的 Python 字典对象
kwds = PyDict_New();
// 如果数据类型不是 NPY_NOTYPE
if (rtype != NPY_NOTYPE) {
// 根据数据类型创建一个 NumPy 数组描述符对象
PyArray_Descr *descr;
descr = PyArray_DescrFromType(rtype);
// 如果描述符对象有效
if (descr) {
// 向字典中添加 "dtype" 键,值为描述符对象的 Python 对象表示
PyDict_SetItemString(kwds, "dtype", (PyObject *)descr);
Py_DECREF(descr);
}
}
// 如果输出对象不为空,则向字典中添加 "out" 键,值为输出对象的 Python 对象表示
if (out != NULL) {
PyDict_SetItemString(kwds, "out", (PyObject *)out);
}
}
// 返回组装好的关键字字典
return kwds;
}
NPY_NO_EXPORT PyObject *
PyArray_GenericReduceFunction(PyArrayObject *m1, PyObject *op, int axis,
int rtype, PyArrayObject *out)
{
PyObject *args, *ret = NULL, *meth;
PyObject *kwds;
// 使用 Py_BuildValue 函数创建一个参数元组,包含 m1 和 axis
args = Py_BuildValue("(Oi)", m1, axis);
// 调用 _get_keywords 函数获取操作关键字字典
kwds = _get_keywords(rtype, out);
// 获取操作对象 op 的 "reduce" 方法
meth = PyObject_GetAttrString(op, "reduce");
// 如果获取成功并且 meth 是可调用的
if (meth && PyCallable_Check(meth)) {
// 调用 meth 方法,传递 args 和 kwds 作为参数
ret = PyObject_Call(meth, args, kwds);
}
// 释放 args 和 meth 对象的引用计数
Py_DECREF(args);
Py_DECREF(meth);
// 释放 kwds 对象的引用计数,使用 Py_XDECREF 避免空指针异常
Py_XDECREF(kwds);
// 返回操作结果
return ret;
}
NPY_NO_EXPORT PyObject *
PyArray_GenericAccumulateFunction(PyArrayObject *m1, PyObject *op, int axis,
int rtype, PyArrayObject *out)
{
PyObject *args, *ret = NULL, *meth;
PyObject *kwds;
// 使用 Py_BuildValue 函数创建一个参数元组,包含 m1 和 axis
args = Py_BuildValue("(Oi)", m1, axis);
// 调用 _get_keywords 函数获取操作关键字字典
kwds = _get_keywords(rtype, out);
// 获取操作对象 op 的 "accumulate" 方法
meth = PyObject_GetAttrString(op, "accumulate");
// 如果获取成功并且 meth 是可调用的
if (meth && PyCallable_Check(meth)) {
// 调用 meth 方法,传递 args 和 kwds 作为参数
ret = PyObject_Call(meth, args, kwds);
}
// 释放 args 和 meth 对象的引用计数
Py_DECREF(args);
Py_DECREF(meth);
// 释放 kwds 对象的引用计数,使用 Py_XDECREF 避免空指针异常
Py_XDECREF(kwds);
// 返回操作结果
return ret;
}
NPY_NO_EXPORT PyObject *
PyArray_GenericBinaryFunction(PyObject *m1, PyObject *m2, PyObject *op)
{
// 直接调用 PyObject_CallFunctionObjArgs 函数,传递 op、m1 和 m2 作为参数
return PyObject_CallFunctionObjArgs(op, m1, m2, NULL);
}
NPY_NO_EXPORT PyObject *
PyArray_GenericUnaryFunction(PyArrayObject *m1, PyObject *op)
{
// 直接调用 PyObject_CallFunctionObjArgs 函数,传递 op 和 m1 作为参数
return PyObject_CallFunctionObjArgs(op, m1, NULL);
}
static PyObject *
PyArray_GenericInplaceBinaryFunction(PyArrayObject *m1,
PyObject *m2, PyObject *op)
{
// 直接调用 PyObject_CallFunctionObjArgs 函数,传递 op、m1 和 m2 作为参数
return PyObject_CallFunctionObjArgs(op, m1, m2, m1, NULL);
}
static PyObject *
PyArray_GenericInplaceUnaryFunction(PyArrayObject *m1, PyObject *op)
{
// 直接调用 PyObject_CallFunctionObjArgs 函数,传递 op、m1 和 m1 作为参数
return PyObject_CallFunctionObjArgs(op, m1, m1, NULL);
}
static PyObject *
array_add(PyObject *m1, PyObject *m2)
{
PyObject *res;
// 使用 BINOP_GIVE_UP_IF_NEEDED 宏,处理 m1 和 m2,调用 nb_add 函数或 array_add 函数
BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_add, array_add);
// 尝试使用 try_binary_elide 函数进行二进制操作的优化
if (try_binary_elide(m1, m2, &array_inplace_add, &res, 1)) {
return res;
}
// 调用 PyArray_GenericBinaryFunction 函数进行通用的二元操作
return PyArray_GenericBinaryFunction(m1, m2, n_ops.add);
}
static PyObject *
array_subtract(PyObject *m1, PyObject *m2)
{
PyObject *res;
// 使用 BINOP_GIVE_UP_IF_NEEDED 宏,处理 m1 和 m2,调用 nb_subtract 函数或 array_subtract 函数
BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_subtract, array_subtract);
// 尝试使用 try_binary_elide 函数进行二进制操作的优化
if (try_binary_elide(m1, m2, &array_inplace_subtract, &res, 0)) {
return res;
}
// 调用 PyArray_GenericBinaryFunction 函数进行通用的二元操作
return PyArray_GenericBinaryFunction(m1, m2, n_ops.subtract);
}
static PyObject *
array_multiply(PyObject *m1, PyObject *m2)
{
PyObject *res;
// 使用 BINOP_GIVE_UP_IF_NEEDED 宏,处理 m1 和 m2,调用 nb_multiply 函数或 array_multiply 函数
BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_multiply, array_multiply);
// 尝试使用 try_binary_elide 函数进行二进制操作的优化
if (try_binary_elide(m1, m2, &array_inplace_multiply, &res, 0)) {
return res;
}
// 调用 PyArray_GenericBinaryFunction 函数进行通用的二元操作
return PyArray_GenericBinaryFunction(m1, m2, n_ops.multiply);
}
BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_multiply, array_multiply);
if (try_binary_elide(m1, m2, &array_inplace_multiply, &res, 1)) {
return res;
}
return PyArray_GenericBinaryFunction(m1, m2, n_ops.multiply);
/*
* 返回 PyArray_GenericBinaryFunction 的余数计算结果
* 如果需要,使用宏 BINOP_GIVE_UP_IF_NEEDED 确保 m1 和 m2 是有效的操作数
*/
static PyObject *
array_remainder(PyObject *m1, PyObject *m2)
{
BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_remainder, array_remainder);
return PyArray_GenericBinaryFunction(m1, m2, n_ops.remainder);
}
/*
* 返回 PyArray_GenericBinaryFunction 的商余运算结果
* 使用宏 BINOP_GIVE_UP_IF_NEEDED 确保 m1 和 m2 是有效的操作数
*/
static PyObject *
array_divmod(PyObject *m1, PyObject *m2)
{
BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_divmod, array_divmod);
return PyArray_GenericBinaryFunction(m1, m2, n_ops.divmod);
}
/*
* 返回 PyArray_GenericBinaryFunction 的矩阵乘法结果
* 使用宏 BINOP_GIVE_UP_IF_NEEDED 确保 m1 和 m2 是有效的操作数
*/
static PyObject *
array_matrix_multiply(PyObject *m1, PyObject *m2)
{
BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_matrix_multiply, array_matrix_multiply);
return PyArray_GenericBinaryFunction(m1, m2, n_ops.matmul);
}
/*
* 原地执行矩阵乘法,并返回结果
* 使用 INPLACE_GIVE_UP_IF_NEEDED 宏确保 self 和 other 是有效的操作数
* 根据 self 的维度数选择正确的 kwargs,用于调用 n_ops.matmul
* 如果操作失败,根据错误类型设置相应的错误信息
*/
static PyObject *
array_inplace_matrix_multiply(PyArrayObject *self, PyObject *other)
{
INPLACE_GIVE_UP_IF_NEEDED(self, other,
nb_inplace_matrix_multiply, array_inplace_matrix_multiply);
PyObject *args = PyTuple_Pack(3, self, other, self);
if (args == NULL) {
return NULL;
}
PyObject *kwargs;
/*
* 不像 `matmul(a, b, out=a)`,我们确保结果不会进行广播,
* 如果没有 `out` 参数,结果维度比 `a` 少。
* 因为 matmul 的签名是 '(n?,k),(k,m?)->(n?,m?)',这种情况正好是第二个操作数具有核心维度的情况。
*
* 这里的错误可能会令人困惑,但现在我们通过传递正确的 `axes=` 来强制执行。
*/
if (PyArray_NDIM(self) == 1) {
kwargs = npy_static_pydata.axes_1d_obj_kwargs;
}
else {
kwargs = npy_static_pydata.axes_2d_obj_kwargs;
}
PyObject *res = PyObject_Call(n_ops.matmul, args, kwargs);
Py_DECREF(args);
if (res == NULL) {
/*
* 如果异常是 AxisError,说明 axes 参数设置不正确,
* 这通常是因为第二个操作数不是二维的。
*/
if (PyErr_ExceptionMatches(npy_static_pydata.AxisError)) {
PyErr_SetString(PyExc_ValueError,
"inplace matrix multiplication requires the first operand to "
"have at least one and the second at least two dimensions.");
}
}
return res;
}
/*
* 确定对象是否是标量,并在是标量时将其转换为双精度数,
* 将结果放入 out_exponent 参数中,并返回相应的“标量种类”。
* 如果对象不是标量(或有其他错误条件),返回 NPY_NOSCALAR,out_exponent 未定义。
*/
static NPY_SCALARKIND
is_scalar_with_conversion(PyObject *o2, double* out_exponent)
{
PyObject *temp;
const int optimize_fpexps = 1;
if (PyLong_Check(o2)) {
long tmp = PyLong_AsLong(o2);
if (error_converting(tmp)) {
PyErr_Clear();
return NPY_NOSCALAR;
}
*out_exponent = (double)tmp;
return NPY_INTPOS_SCALAR;
}
if (optimize_fpexps && PyFloat_Check(o2)) {
*out_exponent = PyFloat_AsDouble(o2);
return NPY_FLOAT_SCALAR;
}
/* 继续处理其他类型的标量情况 */
if (PyArray_Check(o2)) {
if ((PyArray_NDIM((PyArrayObject *)o2) == 0) &&
((PyArray_ISINTEGER((PyArrayObject *)o2) ||
(optimize_fpexps && PyArray_ISFLOAT((PyArrayObject *)o2))))) {
temp = Py_TYPE(o2)->tp_as_number->nb_float(o2);
if (temp == NULL) {
return NPY_NOSCALAR;
}
*out_exponent = PyFloat_AsDouble(o2);
Py_DECREF(temp);
if (PyArray_ISINTEGER((PyArrayObject *)o2)) {
return NPY_INTPOS_SCALAR;
}
else { /* ISFLOAT */
return NPY_FLOAT_SCALAR;
}
}
}
else if (PyArray_IsScalar(o2, Integer) ||
(optimize_fpexps && PyArray_IsScalar(o2, Floating))) {
temp = Py_TYPE(o2)->tp_as_number->nb_float(o2);
if (temp == NULL) {
return NPY_NOSCALAR;
}
*out_exponent = PyFloat_AsDouble(o2);
Py_DECREF(temp);
if (PyArray_IsScalar(o2, Integer)) {
return NPY_INTPOS_SCALAR;
}
else { /* IsScalar(o2, Floating) */
return NPY_FLOAT_SCALAR;
}
}
else if (PyIndex_Check(o2)) {
PyObject* value = PyNumber_Index(o2);
Py_ssize_t val;
if (value == NULL) {
if (PyErr_Occurred()) {
PyErr_Clear();
}
return NPY_NOSCALAR;
}
val = PyLong_AsSsize_t(value);
Py_DECREF(value);
if (error_converting(val)) {
PyErr_Clear();
return NPY_NOSCALAR;
}
*out_exponent = (double) val;
return NPY_INTPOS_SCALAR;
}
return NPY_NOSCALAR;
/*
* optimize float array or complex array to a scalar power
* returns 0 on success, -1 if no optimization is possible
* the result is in value (can be NULL if an error occurred)
*/
static int
fast_scalar_power(PyObject *o1, PyObject *o2, int inplace,
PyObject **value)
{
double exponent;
NPY_SCALARKIND kind; /* NPY_NOSCALAR is not scalar */
// 检查 o1 是否是数组,并且不是对象数组,同时尝试从 o2 中提取指数值
if (PyArray_Check(o1) &&
!PyArray_ISOBJECT((PyArrayObject *)o1) &&
((kind=is_scalar_with_conversion(o2, &exponent))>0)) {
PyArrayObject *a1 = (PyArrayObject *)o1;
PyObject *fastop = NULL;
// 如果数组是浮点数或复数类型
if (PyArray_ISFLOAT(a1) || PyArray_ISCOMPLEX(a1)) {
// 根据指数值选择合适的快速操作函数
if (exponent == 1.0) {
fastop = n_ops.positive;
}
else if (exponent == -1.0) {
fastop = n_ops.reciprocal;
}
else if (exponent == 0.0) {
fastop = n_ops._ones_like;
}
else if (exponent == 0.5) {
fastop = n_ops.sqrt;
}
else if (exponent == 2.0) {
fastop = n_ops.square;
}
else {
return -1; // 如果找不到匹配的快速操作,返回 -1
}
// 根据 inplace 标志选择相应的操作函数
if (inplace || can_elide_temp_unary(a1)) {
*value = PyArray_GenericInplaceUnaryFunction(a1, fastop);
}
else {
*value = PyArray_GenericUnaryFunction(a1, fastop);
}
return 0; // 返回成功标志
}
// 对于指数为 2.0 的情况,特殊处理
else if (exponent == 2.0) {
fastop = n_ops.square;
// 如果 inplace 标志为真,则使用原地操作函数
if (inplace) {
*value = PyArray_GenericInplaceUnaryFunction(a1, fastop);
}
else {
// 只有 FLOAT_SCALAR 和整数类型会特别处理
if (kind == NPY_FLOAT_SCALAR && PyArray_ISINTEGER(a1)) {
// 将数组类型转换为双精度浮点型
PyArray_Descr *dtype = PyArray_DescrFromType(NPY_DOUBLE);
a1 = (PyArrayObject *)PyArray_CastToType(a1, dtype,
PyArray_ISFORTRAN(a1));
if (a1 != NULL) {
// 执行转换后的操作
*value = PyArray_GenericInplaceUnaryFunction(a1, fastop);
Py_DECREF(a1);
}
}
else {
// 否则,使用一般的操作函数
*value = PyArray_GenericUnaryFunction(a1, fastop);
}
}
return 0; // 返回成功标志
}
}
// 如果没有找到适合的快速操作,返回 -1
return -1;
}
static PyObject *
array_power(PyObject *a1, PyObject *o2, PyObject *modulo)
{
PyObject *value = NULL;
if (modulo != Py_None) {
/* 如果给定的模数不是 None,则返回 NotImplemented
这里暂时不支持模幂运算(gh-8804)
*/
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
BINOP_GIVE_UP_IF_NEEDED(a1, o2, nb_power, array_power);
/* 如果需要放弃,此处进行操作,包括传递参数 a1, o2, nb_power, array_power */
if (fast_scalar_power(a1, o2, 0, &value) != 0) {
/* 如果快速标量幂运算返回非零值,表示出错,则使用通用的数组二元函数来计算结果
使用参数 a1, o2, n_ops.power 调用 PyArray_GenericBinaryFunction 函数
*/
value = PyArray_GenericBinaryFunction(a1, o2, n_ops.power);
}
/* 返回计算得到的 value */
return value;
static PyObject *
array_positive(PyArrayObject *m1)
{
// 检查是否可以省略临时一元操作
if (can_elide_temp_unary(m1)) {
// 如果可以省略,则使用原地一元函数执行正操作
return PyArray_GenericInplaceUnaryFunction(m1, n_ops.positive);
}
// 否则,使用通用一元函数执行正操作
return PyArray_GenericUnaryFunction(m1, n_ops.positive);
}
static PyObject *
array_negative(PyArrayObject *m1)
{
// 检查是否可以省略临时一元操作
if (can_elide_temp_unary(m1)) {
// 如果可以省略,则使用原地一元函数执行负操作
return PyArray_GenericInplaceUnaryFunction(m1, n_ops.negative);
}
// 否则,使用通用一元函数执行负操作
return PyArray_GenericUnaryFunction(m1, n_ops.negative);
}
static PyObject *
array_absolute(PyArrayObject *m1)
{
// 检查是否可以省略临时一元操作并且不是复数数组
if (can_elide_temp_unary(m1) && !PyArray_ISCOMPLEX(m1)) {
// 如果可以省略且不是复数数组,则使用原地一元函数执行绝对值操作
return PyArray_GenericInplaceUnaryFunction(m1, n_ops.absolute);
}
// 否则,使用通用一元函数执行绝对值操作
return PyArray_GenericUnaryFunction(m1, n_ops.absolute);
}
static PyObject *
array_invert(PyArrayObject *m1)
{
// 检查是否可以省略临时一元操作
if (can_elide_temp_unary(m1)) {
// 如果可以省略,则使用原地一元函数执行按位取反操作
return PyArray_GenericInplaceUnaryFunction(m1, n_ops.invert);
}
// 否则,使用通用一元函数执行按位取反操作
return PyArray_GenericUnaryFunction(m1, n_ops.invert);
}
static PyObject *
array_left_shift(PyObject *m1, PyObject *m2)
{
PyObject *res;
// 如果必要,放弃二元操作
BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_lshift, array_left_shift);
// 尝试省略二元操作
if (try_binary_elide(m1, m2, &array_inplace_left_shift, &res, 0)) {
return res;
}
// 否则,使用通用二元函数执行左移操作
return PyArray_GenericBinaryFunction(m1, m2, n_ops.left_shift);
}
static PyObject *
array_right_shift(PyObject *m1, PyObject *m2)
{
PyObject *res;
// 如果必要,放弃二元操作
BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_rshift, array_right_shift);
// 尝试省略二元操作
if (try_binary_elide(m1, m2, &array_inplace_right_shift, &res, 0)) {
return res;
}
// 否则,使用通用二元函数执行右移操作
return PyArray_GenericBinaryFunction(m1, m2, n_ops.right_shift);
}
static PyObject *
array_bitwise_and(PyObject *m1, PyObject *m2)
{
PyObject *res;
// 如果必要,放弃二元操作
BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_and, array_bitwise_and);
// 尝试省略二元操作
if (try_binary_elide(m1, m2, &array_inplace_bitwise_and, &res, 1)) {
return res;
}
// 否则,使用通用二元函数执行按位与操作
return PyArray_GenericBinaryFunction(m1, m2, n_ops.bitwise_and);
}
static PyObject *
array_bitwise_or(PyObject *m1, PyObject *m2)
{
PyObject *res;
// 如果必要,放弃二元操作
BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_or, array_bitwise_or);
// 尝试省略二元操作
if (try_binary_elide(m1, m2, &array_inplace_bitwise_or, &res, 1)) {
return res;
}
// 否则,使用通用二元函数执行按位或操作
return PyArray_GenericBinaryFunction(m1, m2, n_ops.bitwise_or);
}
static PyObject *
array_bitwise_xor(PyObject *m1, PyObject *m2)
{
PyObject *res;
// 如果必要,放弃二元操作
BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_xor, array_bitwise_xor);
// 尝试省略二元操作
if (try_binary_elide(m1, m2, &array_inplace_bitwise_xor, &res, 1)) {
return res;
}
// 否则,使用通用二元函数执行按位异或操作
return PyArray_GenericBinaryFunction(m1, m2, n_ops.bitwise_xor);
}
static PyObject *
array_inplace_add(PyArrayObject *m1, PyObject *m2)
{
// 如果必要,放弃原地二元操作
INPLACE_GIVE_UP_IF_NEEDED(
m1, m2, nb_inplace_add, array_inplace_add);
// 使用通用原地二元函数执行加法操作
return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.add);
}
static PyObject *
array_inplace_subtract(PyArrayObject *m1, PyObject *m2)
{
// 如果必要,放弃原地二元操作
INPLACE_GIVE_UP_IF_NEEDED(
m1, m2, nb_inplace_subtract, array_inplace_subtract);
return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.subtract);
static PyObject *
array_inplace_multiply(PyArrayObject *m1, PyObject *m2)
{
// 如果需要放弃原地操作,则直接返回
INPLACE_GIVE_UP_IF_NEEDED(
m1, m2, nb_inplace_multiply, array_inplace_multiply);
// 使用通用的原地二进制函数处理乘法操作
return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.multiply);
}
static PyObject *
array_inplace_remainder(PyArrayObject *m1, PyObject *m2)
{
// 如果需要放弃原地操作,则直接返回
INPLACE_GIVE_UP_IF_NEEDED(
m1, m2, nb_inplace_remainder, array_inplace_remainder);
// 使用通用的原地二进制函数处理取余操作
return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.remainder);
}
static PyObject *
array_inplace_power(PyArrayObject *a1, PyObject *o2, PyObject *NPY_UNUSED(modulo))
{
/* modulo is ignored! */
// 忽略掉 modulo 参数
PyObject *value = NULL;
// 如果需要放弃原地操作,则直接返回
INPLACE_GIVE_UP_IF_NEEDED(
a1, o2, nb_inplace_power, array_inplace_power);
// 尝试使用快速标量幂运算,如果失败则使用通用的原地二进制函数处理幂运算
if (fast_scalar_power((PyObject *)a1, o2, 1, &value) != 0) {
value = PyArray_GenericInplaceBinaryFunction(a1, o2, n_ops.power);
}
return value;
}
static PyObject *
array_inplace_left_shift(PyArrayObject *m1, PyObject *m2)
{
// 如果需要放弃原地操作,则直接返回
INPLACE_GIVE_UP_IF_NEEDED(
m1, m2, nb_inplace_lshift, array_inplace_left_shift);
// 使用通用的原地二进制函数处理左移操作
return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.left_shift);
}
static PyObject *
array_inplace_right_shift(PyArrayObject *m1, PyObject *m2)
{
// 如果需要放弃原地操作,则直接返回
INPLACE_GIVE_UP_IF_NEEDED(
m1, m2, nb_inplace_rshift, array_inplace_right_shift);
// 使用通用的原地二进制函数处理右移操作
return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.right_shift);
}
static PyObject *
array_inplace_bitwise_and(PyArrayObject *m1, PyObject *m2)
{
// 如果需要放弃原地操作,则直接返回
INPLACE_GIVE_UP_IF_NEEDED(
m1, m2, nb_inplace_and, array_inplace_bitwise_and);
// 使用通用的原地二进制函数处理按位与操作
return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.bitwise_and);
}
static PyObject *
array_inplace_bitwise_or(PyArrayObject *m1, PyObject *m2)
{
// 如果需要放弃原地操作,则直接返回
INPLACE_GIVE_UP_IF_NEEDED(
m1, m2, nb_inplace_or, array_inplace_bitwise_or);
// 使用通用的原地二进制函数处理按位或操作
return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.bitwise_or);
}
static PyObject *
array_inplace_bitwise_xor(PyArrayObject *m1, PyObject *m2)
{
// 如果需要放弃原地操作,则直接返回
INPLACE_GIVE_UP_IF_NEEDED(
m1, m2, nb_inplace_xor, array_inplace_bitwise_xor);
// 使用通用的原地二进制函数处理按位异或操作
return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.bitwise_xor);
}
static PyObject *
array_floor_divide(PyObject *m1, PyObject *m2)
{
PyObject *res;
// 如果需要放弃二进制操作,则直接返回
BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_floor_divide, array_floor_divide);
// 尝试通过二进制简化操作执行地板除法,如果成功则返回结果
if (try_binary_elide(m1, m2, &array_inplace_floor_divide, &res, 0)) {
return res;
}
// 使用通用的二进制函数处理地板除法
return PyArray_GenericBinaryFunction(m1, m2, n_ops.floor_divide);
}
static PyObject *
array_true_divide(PyObject *m1, PyObject *m2)
{
PyObject *res;
PyArrayObject *a1 = (PyArrayObject *)m1;
// 如果需要放弃二进制操作,则直接返回
BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_true_divide, array_true_divide);
// 如果 m1 是精确的数组对象,并且是浮点型或复数型,并且可以尝试简化二进制操作,则返回结果
if (PyArray_CheckExact(m1) &&
(PyArray_ISFLOAT(a1) || PyArray_ISCOMPLEX(a1)) &&
try_binary_elide(m1, m2, &array_inplace_true_divide, &res, 0)) {
return res;
}
// 使用通用的二进制函数处理真除法
return PyArray_GenericBinaryFunction(m1, m2, n_ops.true_divide);
}
/*
* Perform inplace floor division on two NumPy arrays.
* If necessary, give up inplace operation and revert to generic operation.
*/
static PyObject *
array_inplace_floor_divide(PyArrayObject *m1, PyObject *m2)
{
INPLACE_GIVE_UP_IF_NEEDED(
m1, m2, nb_inplace_floor_divide, array_inplace_floor_divide);
// Call a generic inplace binary function for floor division
return PyArray_GenericInplaceBinaryFunction(m1, m2,
n_ops.floor_divide);
}
/*
* Perform inplace true division on two NumPy arrays.
* If necessary, give up inplace operation and revert to generic operation.
*/
static PyObject *
array_inplace_true_divide(PyArrayObject *m1, PyObject *m2)
{
INPLACE_GIVE_UP_IF_NEEDED(
m1, m2, nb_inplace_true_divide, array_inplace_true_divide);
// Call a generic inplace binary function for true division
return PyArray_GenericInplaceBinaryFunction(m1, m2,
n_ops.true_divide);
}
/*
* Check if a NumPy array is nonzero.
* If the array has one element, convert to bool; handle potential recursion.
* If the array has zero elements, issue a deprecation warning.
* If the array has more than one element, raise a ValueError.
*/
static int
_array_nonzero(PyArrayObject *mp)
{
npy_intp n;
n = PyArray_SIZE(mp);
if (n == 1) {
int res;
if (Py_EnterRecursiveCall(" while converting array to bool")) {
return -1;
}
// Get the nonzero function from array descriptor and apply to data
res = PyDataType_GetArrFuncs(PyArray_DESCR(mp))->nonzero(PyArray_DATA(mp), mp);
/* nonzero has no way to indicate an error, but one can occur */
if (PyErr_Occurred()) {
res = -1;
}
Py_LeaveRecursiveCall();
return res;
}
else if (n == 0) {
/* 2017-09-25, 1.14 */
// Issue deprecation warning for truth value of empty array
if (DEPRECATE("The truth value of an empty array is ambiguous. "
"Returning False, but in future this will result in an error. "
"Use `array.size > 0` to check that an array is not empty.") < 0) {
return -1;
}
return 0;
}
else {
// Raise ValueError for ambiguous truth value of array with more than one element
PyErr_SetString(PyExc_ValueError,
"The truth value of an array "
"with more than one element is ambiguous. "
"Use a.any() or a.all()");
return -1;
}
}
/*
* Convert a NumPy array to a scalar if allowed, and apply the given builtin function to it.
* Handle recursion if array holds references.
*/
NPY_NO_EXPORT PyObject *
array_scalar_forward(PyArrayObject *v,
PyObject *(*builtin_func)(PyObject *),
const char *where)
{
// Check if the array can be converted to a scalar
if (check_is_convertible_to_scalar(v) < 0) {
return NULL;
}
PyObject *scalar;
scalar = PyArray_GETITEM(v, PyArray_DATA(v));
if (scalar == NULL) {
return NULL;
}
/* Need to guard against recursion if our array holds references */
if (PyDataType_REFCHK(PyArray_DESCR(v))) {
PyObject *res;
// Enter recursion guard with given location string
if (Py_EnterRecursiveCall(where) != 0) {
Py_DECREF(scalar);
return NULL;
}
// Apply builtin_func to scalar and handle recursion exit
res = builtin_func(scalar);
Py_DECREF(scalar);
Py_LeaveRecursiveCall();
return res;
}
else {
// Apply builtin_func to scalar without recursion handling
PyObject *res;
res = builtin_func(scalar);
Py_DECREF(scalar);
return res;
}
}
/*
* Convert a NumPy array to a floating-point scalar.
*/
NPY_NO_EXPORT PyObject *
array_float(PyArrayObject *v)
{
// Forward array to scalar conversion for float
return array_scalar_forward(v, &PyNumber_Float, " in ndarray.__float__");
}
// 定义函数 `array_int`,接受一个 PyArrayObject 类型的参数 `v`,并将其传递给 `array_scalar_forward` 函数进行处理,返回处理结果
array_int(PyArrayObject *v)
{
// 调用 `array_scalar_forward` 函数,传递参数 `v` 和 `&PyNumber_Long`,并附加错误信息字符串 " in ndarray.__int__"
return array_scalar_forward(v, &PyNumber_Long, " in ndarray.__int__");
}
// 定义静态函数 `array_index`,接受一个 PyArrayObject 类型的参数 `v`
static PyObject *
array_index(PyArrayObject *v)
{
// 如果 `v` 不是整数标量数组或者不是零维数组
if (!PyArray_ISINTEGER(v) || PyArray_NDIM(v) != 0) {
// 设置类型错误异常,并返回 NULL
PyErr_SetString(PyExc_TypeError,
"only integer scalar arrays can be converted to a scalar index");
return NULL;
}
// 返回 `v` 的数据部分对应的 Python 对象
return PyArray_GETITEM(v, PyArray_DATA(v));
}
// 定义 `array_as_number` 结构体,实现 PyNumberMethods 结构体
NPY_NO_EXPORT PyNumberMethods array_as_number = {
// 定义各种数学运算方法
.nb_add = array_add,
.nb_subtract = array_subtract,
.nb_multiply = array_multiply,
.nb_remainder = array_remainder,
.nb_divmod = array_divmod,
.nb_power = (ternaryfunc)array_power,
.nb_negative = (unaryfunc)array_negative,
.nb_positive = (unaryfunc)array_positive,
.nb_absolute = (unaryfunc)array_absolute,
.nb_bool = (inquiry)_array_nonzero,
.nb_invert = (unaryfunc)array_invert,
.nb_lshift = array_left_shift,
.nb_rshift = array_right_shift,
.nb_and = array_bitwise_and,
.nb_xor = array_bitwise_xor,
.nb_or = array_bitwise_or,
// 类型转换方法
.nb_int = (unaryfunc)array_int,
.nb_float = (unaryfunc)array_float,
// 原地运算方法
.nb_inplace_add = (binaryfunc)array_inplace_add,
.nb_inplace_subtract = (binaryfunc)array_inplace_subtract,
.nb_inplace_multiply = (binaryfunc)array_inplace_multiply,
.nb_inplace_remainder = (binaryfunc)array_inplace_remainder,
.nb_inplace_power = (ternaryfunc)array_inplace_power,
.nb_inplace_lshift = (binaryfunc)array_inplace_left_shift,
.nb_inplace_rshift = (binaryfunc)array_inplace_right_shift,
.nb_inplace_and = (binaryfunc)array_inplace_bitwise_and,
.nb_inplace_xor = (binaryfunc)array_inplace_bitwise_xor,
.nb_inplace_or = (binaryfunc)array_inplace_bitwise_or,
// 浮点数运算方法
.nb_floor_divide = array_floor_divide,
.nb_true_divide = array_true_divide,
.nb_inplace_floor_divide = (binaryfunc)array_inplace_floor_divide,
.nb_inplace_true_divide = (binaryfunc)array_inplace_true_divide,
// 返回整数索引的方法
.nb_index = (unaryfunc)array_index,
// 矩阵乘法方法
.nb_matrix_multiply = array_matrix_multiply,
.nb_inplace_matrix_multiply = (binaryfunc)array_inplace_matrix_multiply,
};
.\numpy\numpy\_core\src\multiarray\number.h
// 如果未定义 NUMPY_CORE_SRC_MULTIARRAY_NUMBER_H_ 宏,则开始条件编译防护
// 定义 NumericOps 结构体,用于存储各种数值操作的函数指针
typedef struct {
PyObject *add; // 加法
PyObject *subtract; // 减法
PyObject *multiply; // 乘法
PyObject *divide; // 除法
PyObject *remainder; // 求余
PyObject *divmod; // 返回除法结果和余数
PyObject *power; // 指数运算
PyObject *square; // 平方
PyObject *reciprocal; // 倒数
PyObject *_ones_like; // 类似 ones 的操作
PyObject *sqrt; // 平方根
PyObject *cbrt; // 立方根
PyObject *negative; // 取负
PyObject *positive; // 取正
PyObject *absolute; // 绝对值
PyObject *invert; // 按位取反
PyObject *left_shift; // 左移
PyObject *right_shift; // 右移
PyObject *bitwise_and; // 按位与
PyObject *bitwise_xor; // 按位异或
PyObject *bitwise_or; // 按位或
PyObject *less; // 小于比较
PyObject *less_equal; // 小于等于比较
PyObject *equal; // 等于比较
PyObject *not_equal; // 不等于比较
PyObject *greater; // 大于比较
PyObject *greater_equal; // 大于等于比较
PyObject *floor_divide; // 地板除
PyObject *true_divide; // 真除
PyObject *logical_or; // 逻辑或
PyObject *logical_and; // 逻辑与
PyObject *floor; // 向下取整
PyObject *ceil; // 向上取整
PyObject *maximum; // 最大值
PyObject *minimum; // 最小值
PyObject *rint; // 四舍五入到最接近的整数
PyObject *conjugate; // 复数的共轭
PyObject *matmul; // 矩阵乘法
PyObject *clip; // 裁剪
} NumericOps;
// 声明外部的 NumericOps 结构体变量 n_ops
extern NPY_NO_EXPORT NumericOps n_ops;
// 声明外部的 PyNumberMethods 结构体变量 array_as_number
extern NPY_NO_EXPORT PyNumberMethods array_as_number;
// 声明 PyArrayObject 到 PyObject 的类型转换函数
NPY_NO_EXPORT PyObject *
array_int(PyArrayObject *v);
// 声明设置 NumericOps 的函数,参数为一个 PyObject 字典
NPY_NO_EXPORT int
_PyArray_SetNumericOps(PyObject *dict);
// 声明通用的二元操作函数,参数为两个 PyObject 和一个操作符对象
NPY_NO_EXPORT PyObject *
PyArray_GenericBinaryFunction(PyObject *m1, PyObject *m2, PyObject *op);
// 声明通用的一元操作函数,参数为一个 PyArrayObject 和一个操作符对象
NPY_NO_EXPORT PyObject *
PyArray_GenericUnaryFunction(PyArrayObject *m1, PyObject *op);
// 声明通用的约简操作函数,参数包括一个 PyArrayObject,一个操作符对象,一个轴,一个返回类型和一个输出数组对象
NPY_NO_EXPORT PyObject *
PyArray_GenericReduceFunction(PyArrayObject *m1, PyObject *op, int axis,
int rtype, PyArrayObject *out);
// 声明通用的累积操作函数,参数包括一个 PyArrayObject,一个操作符对象,一个轴,一个返回类型和一个输出数组对象
NPY_NO_EXPORT PyObject *
PyArray_GenericAccumulateFunction(PyArrayObject *m1, PyObject *op, int axis,
int rtype, PyArrayObject *out);
// 结束条件编译防护,确保只有在未定义时才会包含该文件
.\numpy\numpy\_core\src\multiarray\public_dtype_api.c
/*NUMPY_API
*
* Initialize a new DType. It must currently be a static Python C type that
* is declared as `PyArray_DTypeMeta` and not `PyTypeObject`. Further, it
* must subclass `np.dtype` and set its type to `PyArrayDTypeMeta_Type`
* (before calling `PyType_Ready()`). The DTypeMeta object has additional
* fields compared to a normal PyTypeObject!
*/
int
PyArrayInitDTypeMeta_FromSpec(
PyArray_DTypeMeta *DType, PyArrayDTypeMeta_Spec *spec)
{
/* 检查传入的 DType 是否是有效的 DTypeMeta 实例 */
if (!PyObject_TypeCheck(DType, &PyArrayDTypeMeta_Type)) {
PyErr_SetString(PyExc_RuntimeError,
"Passed in DType must be a valid (initialized) DTypeMeta "
"instance!");
return -1;
}
/* 检查自定义 DType 是否实现了 `__repr__` 和 `__str__` 方法 */
if (((PyTypeObject *)DType)->tp_repr == PyArrayDescr_Type.tp_repr
|| ((PyTypeObject *)DType)->tp_str == PyArrayDescr_Type.tp_str) {
PyErr_SetString(PyExc_TypeError,
"A custom DType must implement `__repr__` and `__str__` since "
"the default inherited version (currently) fails.");
return -1;
}
/* 检查 spec->typeobj 是否为有效的类型对象 */
if (spec->typeobj == NULL || !PyType_Check(spec->typeobj)) {
PyErr_SetString(PyExc_TypeError,
"Not giving a type object is currently not supported, but "
"is expected to be supported eventually. This would mean "
"that e.g. indexing a NumPy array will return a 0-D array "
"and not a scalar.");
return -1;
}
/* 检查和处理 flags */
int allowed_flags = NPY_DT_PARAMETRIC | NPY_DT_ABSTRACT | NPY_DT_NUMERIC;
if (spec->flags & ~(allowed_flags)) {
PyErr_SetString(PyExc_RuntimeError,
"invalid DType flags specified, only NPY_DT_PARAMETRIC, "
"NPY_DT_ABSTRACT, and NPY_DT_NUMERIC are valid flags for "
"user DTypes.");
return -1;
}
/* 检查 spec->casts 是否为 NULL */
if (spec->casts == NULL) {
PyErr_SetString(
PyExc_RuntimeError,
"DType must at least provide a function to cast (or just copy) "
"between its own instances!");
return -1;
}
/* 初始化 DTypeMeta 结构体 */
dtypemeta_initialize_struct_from_spec(DType, spec, 0);
/* 检查 DType 是否提供了 setitem 和 getitem 方法 */
if (NPY_DT_SLOTS(DType)->setitem == NULL
|| NPY_DT_SLOTS(DType)->getitem == NULL) {
PyErr_SetString(PyExc_RuntimeError,
"A DType must provide a getitem/setitem (there may be an "
"exception here in the future if no scalar type is provided)");
return -1;
}
if (NPY_DT_SLOTS(DType)->ensure_canonical == NULL) {
PyErr_SetString(PyExc_RuntimeError,
"A DType must provide an ensure_canonical implementation.");
return -1;
}
"""
* 现在规范已经读取,我们可以检查用户是否定义了所有必需的函数。
"""
if (spec->flags & NPY_DT_PARAMETRIC) {
if (NPY_DT_SLOTS(DType)->common_instance == NULL ||
NPY_DT_SLOTS(DType)->discover_descr_from_pyobject
== &dtypemeta_discover_as_default) {
PyErr_SetString(PyExc_RuntimeError,
"Parametric DType must define a common-instance and "
"descriptor discovery function!");
return -1;
}
}
if (NPY_DT_SLOTS(DType)->within_dtype_castingimpl == NULL) {
"""
* 我们暂时期望这样。对于只支持简单复制(可能还涉及字节顺序)的 DType,我们应该有一个默认值。
"""
PyErr_SetString(PyExc_RuntimeError,
"DType must provide a function to cast (or just copy) between "
"its own instances!");
return -1;
}
"""
* 最后,我们必须注册所有的类型转换!
"""
return 0;
void
_fill_dtype_api(void *full_api_table[])
{
void **api_table = full_api_table + 320;
/* The type of the DType metaclass */
api_table[0] = &PyArrayDTypeMeta_Type;
/* Boolean */
api_table[1] = &PyArray_BoolDType;
/* Integers */
api_table[2] = &PyArray_ByteDType;
api_table[3] = &PyArray_UByteDType;
api_table[4] = &PyArray_ShortDType;
api_table[5] = &PyArray_UShortDType;
api_table[6] = &PyArray_IntDType;
api_table[7] = &PyArray_UIntDType;
api_table[8] = &PyArray_LongDType;
api_table[9] = &PyArray_ULongDType;
api_table[10] = &PyArray_LongLongDType;
api_table[11] = &PyArray_ULongLongDType;
/* Integer aliases */
api_table[12] = &PyArray_Int8DType;
api_table[13] = &PyArray_UInt8DType;
api_table[14] = &PyArray_Int16DType;
api_table[15] = &PyArray_UInt16DType;
api_table[16] = &PyArray_Int32DType;
api_table[17] = &PyArray_UInt32DType;
api_table[18] = &PyArray_Int64DType;
api_table[19] = &PyArray_UInt64DType;
api_table[20] = &PyArray_IntpDType;
api_table[21] = &PyArray_UIntpDType;
/* Floats */
api_table[22] = &PyArray_HalfDType;
api_table[23] = &PyArray_FloatDType;
api_table[24] = &PyArray_DoubleDType;
api_table[25] = &PyArray_LongDoubleDType;
/* Complex */
api_table[26] = &PyArray_CFloatDType;
api_table[27] = &PyArray_CDoubleDType;
api_table[28] = &PyArray_CLongDoubleDType;
/* String/Bytes */
api_table[29] = &PyArray_BytesDType;
api_table[30] = &PyArray_UnicodeDType;
/* Datetime/Timedelta */
api_table[31] = &PyArray_DatetimeDType;
api_table[32] = &PyArray_TimedeltaDType;
/* Object and Structured */
api_table[33] = &PyArray_ObjectDType;
api_table[34] = &PyArray_VoidDType;
/* Abstract */
api_table[35] = &PyArray_PyLongDType;
api_table[36] = &PyArray_PyFloatDType;
api_table[37] = &PyArray_PyComplexDType;
api_table[38] = &PyArray_DefaultIntDType;
/* Non-legacy DTypes that are built in to NumPy */
api_table[39] = &PyArray_StringDType;
/* Abstract ones added directly: */
full_api_table[366] = &PyArray_IntAbstractDType;
full_api_table[367] = &PyArray_FloatAbstractDType;
full_api_table[368] = &PyArray_ComplexAbstractDType;
}
.\numpy\numpy\_core\src\multiarray\public_dtype_api.h
/*
* This file exports the private function that exposes the DType API
*
* This file is a stub, all important definitions are in the code file.
*/
// 声明一个不导出的函数 _fill_dtype_api,用于暴露 DType API
NPY_NO_EXPORT void
_fill_dtype_api(void *numpy_api_table[]);
// 结束条件预处理指令,确保头文件只被包含一次
.\numpy\numpy\_core\src\multiarray\refcount.c
/*
* This module corresponds to the `Special functions for NPY_OBJECT`
* section in the numpy reference for C-API.
*/
/*
* Helper function to clear a strided memory (normally or always contiguous)
* from all Python (or other) references. The function does nothing if the
* array dtype does not indicate holding references.
*
* It is safe to call this function more than once, failing here is usually
* critical (during cleanup) and should be set up to minimize the risk or
* avoid it fully.
*/
NPY_NO_EXPORT int
PyArray_ClearBuffer(
PyArray_Descr *descr, char *data,
npy_intp stride, npy_intp size, int aligned)
{
// Check if the array's dtype holds references; if not, return early
if (!PyDataType_REFCHK(descr)) {
return 0;
}
NPY_traverse_info clear_info;
/* Flags unused: float errors do not matter and we do not release GIL */
NPY_ARRAYMETHOD_FLAGS flags_unused;
// Retrieve the function pointer to clear the buffer
if (PyArray_GetClearFunction(
aligned, stride, descr, &clear_info, &flags_unused) < 0) {
return -1;
}
// Call the function to clear the memory
int res = clear_info.func(
NULL, clear_info.descr, data, size, stride, clear_info.auxdata);
NPY_traverse_info_xfree(&clear_info);
return res;
}
/*
* Helper function to clear whole array. It seems plausible that we should
* be able to get away with assuming the array is contiguous.
*
* Must only be called on arrays which own their data (and asserts this).
*/
NPY_NO_EXPORT int
PyArray_ClearArray(PyArrayObject *arr)
{
// Assert that the array owns its data
assert(PyArray_FLAGS(arr) & NPY_ARRAY_OWNDATA);
// Get the descriptor of the array
PyArray_Descr *descr = PyArray_DESCR(arr);
// Check if the array's dtype holds references; if not, return early
if (!PyDataType_REFCHK(descr)) {
return 0;
}
/*
* The contiguous path should cover practically all important cases since
* it is difficult to create a non-contiguous array which owns its memory
* and only arrays which own their memory should clear it.
*/
int aligned = PyArray_ISALIGNED(arr);
if (PyArray_ISCONTIGUOUS(arr)) {
// Clear the array buffer directly if it is contiguous
return PyArray_ClearBuffer(
descr, PyArray_BYTES(arr), descr->elsize,
PyArray_SIZE(arr), aligned);
}
// Handle the case for non-contiguous arrays
int idim, ndim;
npy_intp shape_it[NPY_MAXDIMS], strides_it[NPY_MAXDIMS];
npy_intp coord[NPY_MAXDIMS];
char *data_it;
// Prepare iterator for the array to clear all parts
if (PyArray_PrepareOneRawArrayIter(
PyArray_NDIM(arr), PyArray_DIMS(arr),
PyArray_BYTES(arr), PyArray_STRIDES(arr),
&ndim, shape_it, &data_it, strides_it) < 0) {
return -1;
}
npy_intp inner_stride = strides_it[0];
npy_intp inner_shape = shape_it[0];
NPY_traverse_info clear_info;
NPY_ARRAYMETHOD_FLAGS flags_unused;
if (PyArray_GetClearFunction(
aligned, inner_stride, descr, &clear_info, &flags_unused) < 0) {
return -1;
}
NPY_RAW_ITER_START(idim, ndim, coord, shape_it) {
if (clear_info.func(NULL, clear_info.descr,
data_it, inner_shape, inner_stride, clear_info.auxdata) < 0) {
return -1;
}
} NPY_RAW_ITER_ONE_NEXT(idim, ndim, coord,
shape_it, data_it, strides_it);
return 0;
/*NUMPY_API
* 增加单个数组项中所有对象的引用计数。这对于结构化数据类型来说比较复杂,因为需要提取对象的位置。
* 函数会递归地执行每个嵌套字段或子数组数据类型,例如 `np.dtype([("field1", "O"), ("field2", "f,O", (3,2))])`
*/
NPY_NO_EXPORT void
PyArray_Item_INCREF(char *data, PyArray_Descr *descr)
{
PyObject *temp;
// 如果数据类型不需要引用计数检查,则直接返回
if (!PyDataType_REFCHK(descr)) {
return;
}
// 如果数据类型是 NPY_OBJECT(对象类型)
if (descr->type_num == NPY_OBJECT) {
// 从数据中拷贝对象的指针到临时变量
memcpy(&temp, data, sizeof(temp));
// 增加对象的引用计数
Py_XINCREF(temp);
}
// 如果数据类型有字段(结构化类型)
else if (PyDataType_HASFIELDS(descr)) {
PyObject *key, *value, *title = NULL;
PyArray_Descr *new;
int offset;
Py_ssize_t pos = 0;
// 遍历结构化数据类型的字段
while (PyDict_Next(PyDataType_FIELDS(descr), &pos, &key, &value)) {
// 如果是标题键,则跳过
if (NPY_TITLE_KEY(key, value)) {
continue;
}
// 解析字段值,获取新的数据描述符、偏移量和标题
if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset,
&title)) {
return;
}
// 递归增加字段数据的引用计数
PyArray_Item_INCREF(data + offset, new);
}
}
// 如果数据类型有子数组(子数组类型)
else if (PyDataType_HASSUBARRAY(descr)) {
int size, i, inner_elsize;
// 获取子数组中单个元素的大小
inner_elsize = PyDataType_SUBARRAY(descr)->base->elsize;
// 如果内部元素大小为 0,则直接返回
if (inner_elsize == 0) {
/* 没有任何元素,因此直接返回 */
return;
}
// 子数组在内存中是连续存储的
size = descr->elsize / inner_elsize;
// 遍历子数组中的每个元素,递归增加其引用计数
for (i = 0; i < size; i++){
/* 递归地增加子数组元素的引用计数 */
PyArray_Item_INCREF(data + i * inner_elsize,
PyDataType_SUBARRAY(descr)->base);
}
}
else {
/* 此分支不应该被执行到,如果执行到这里,表示存在问题 */
assert(0);
}
// 函数执行完毕,返回
return;
}
/*NUMPY_API
*
* 减少单个数组项中所有对象的引用计数。这对于结构化数据类型来说比较复杂,因为需要提取对象的位置。
* 函数会递归地执行每个嵌套字段或子数组数据类型,例如 `np.dtype([("field1", "O"), ("field2", "f,O", (3,2))])`
*/
NPY_NO_EXPORT void
PyArray_Item_XDECREF(char *data, PyArray_Descr *descr)
{
PyObject *temp;
// 如果数据类型不需要引用计数检查,则直接返回
if (!PyDataType_REFCHK(descr)) {
return;
}
// 如果数据类型是 NPY_OBJECT(对象类型)
if (descr->type_num == NPY_OBJECT) {
// 从数据中拷贝对象的指针到临时变量
memcpy(&temp, data, sizeof(temp));
// 减少对象的引用计数
Py_XDECREF(temp);
}
// 剩余的分支(结构化类型、子数组类型)在这里不需要处理,因为这些情况不会涉及到减少引用计数的操作
}
else if (PyDataType_HASFIELDS(descr)) {
// 如果描述符包含字段信息
PyObject *key, *value, *title = NULL;
PyArray_Descr *new;
int offset;
Py_ssize_t pos = 0;
// 遍历字段字典
while (PyDict_Next(PyDataType_FIELDS(descr), &pos, &key, &value)) {
// 如果是字段的标题键,则跳过
if (NPY_TITLE_KEY(key, value)) {
continue;
}
// 解析字段值元组,获取新的描述符和偏移量
if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset,
&title)) {
// 解析失败,返回
return;
}
// 释放数据中偏移位置的项目
PyArray_Item_XDECREF(data + offset, new);
}
}
else if (PyDataType_HASSUBARRAY(descr)) {
// 如果描述符有子数组
int size, i, inner_elsize;
// 获取子数组的元素大小
inner_elsize = PyDataType_SUBARRAY(descr)->base->elsize;
// 如果子数组的元素大小为0,说明没有元素,直接返回
if (inner_elsize == 0) {
/* There cannot be any elements, so return */
return;
}
// 计算子数组在内存中的大小
size = descr->elsize / inner_elsize;
// 逐个减少子数组元素的引用计数
for (i = 0; i < size; i++){
/* Recursively decrement the reference count of subarray elements */
PyArray_Item_XDECREF(data + i * inner_elsize,
PyDataType_SUBARRAY(descr)->base);
}
}
else {
// 否则,这条路径不应该被执行到,断言失败
/* This path should not be reachable. */
assert(0);
}
// 返回
return;
/* Used for arrays of python objects to increment the reference count of */
/* every python object in the array. */
/*NUMPY_API
For object arrays, increment all internal references.
*/
NPY_NO_EXPORT int
PyArray_INCREF(PyArrayObject *mp)
{
npy_intp i, n;
PyObject **data;
PyObject *temp;
PyArrayIterObject *it;
// 检查数据类型是否需要引用计数
if (!PyDataType_REFCHK(PyArray_DESCR(mp))) {
return 0;
}
// 如果数据类型不是对象类型,使用迭代器递增引用计数
if (PyArray_DESCR(mp)->type_num != NPY_OBJECT) {
// 创建数组迭代器
it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)mp);
if (it == NULL) {
return -1;
}
// 遍历数组并递增每个元素的引用计数
while(it->index < it->size) {
PyArray_Item_INCREF(it->dataptr, PyArray_DESCR(mp));
PyArray_ITER_NEXT(it);
}
Py_DECREF(it);
return 0;
}
// 如果数组是一段连续的内存块
if (PyArray_ISONESEGMENT(mp)) {
// 获取数组数据指针和大小
data = (PyObject **)PyArray_DATA(mp);
n = PyArray_SIZE(mp);
// 如果数据是对齐的,逐个增加引用计数
if (PyArray_ISALIGNED(mp)) {
for (i = 0; i < n; i++, data++) {
Py_XINCREF(*data);
}
}
// 如果数据未对齐,使用临时变量逐个增加引用计数
else {
for( i = 0; i < n; i++, data++) {
memcpy(&temp, data, sizeof(temp));
Py_XINCREF(temp);
}
}
}
else { /* 处理未对齐的数据 */
// 创建数组迭代器
it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)mp);
if (it == NULL) {
return -1;
}
// 遍历数组并递增每个元素的引用计数
while(it->index < it->size) {
memcpy(&temp, it->dataptr, sizeof(temp));
Py_XINCREF(temp);
PyArray_ITER_NEXT(it);
}
Py_DECREF(it);
}
return 0;
}
/*NUMPY_API
Decrement all internal references for object arrays.
(or arrays with object fields)
The use of this function is strongly discouraged, within NumPy
use PyArray_Clear, which DECREF's and sets everything to NULL and can
work with any dtype.
*/
NPY_NO_EXPORT int
PyArray_XDECREF(PyArrayObject *mp)
{
npy_intp i, n;
PyObject **data;
PyObject *temp;
/*
* 静态分配可以在销毁期间不修改数组的引用计数。
* (静态分配本质上并非必需)
*/
PyArrayIterObject it;
// 检查数据类型是否需要引用计数
if (!PyDataType_REFCHK(PyArray_DESCR(mp))) {
return 0;
}
// 如果数据类型不是对象类型,使用迭代器递减引用计数
if (PyArray_DESCR(mp)->type_num != NPY_OBJECT) {
// 检查数组维度是否超出支持范围
if (PyArray_NDIM(mp) > NPY_MAXDIMS_LEGACY_ITERS) {
PyErr_Format(PyExc_RuntimeError,
"this function only supports up to 32 dimensions but "
"the array has %d.", PyArray_NDIM(mp));
return -1;
}
// 初始化原始迭代器并递减每个元素的引用计数
PyArray_RawIterBaseInit(&it, mp);
while(it.index < it.size) {
PyArray_Item_XDECREF(it.dataptr, PyArray_DESCR(mp));
PyArray_ITER_NEXT(&it);
}
return 0;
}
# 检查是否数组是单一连续段
if (PyArray_ISONESEGMENT(mp)) {
# 获取指向数据指针的指针数组
data = (PyObject **)PyArray_DATA(mp);
# 获取数组元素的数量
n = PyArray_SIZE(mp);
# 如果数组是对齐的
if (PyArray_ISALIGNED(mp)) {
# 逐个释放每个数据指针指向的对象
for (i = 0; i < n; i++, data++) Py_XDECREF(*data);
}
else {
# 如果数组不对齐,使用临时变量逐个释放数据指针指向的对象
for (i = 0; i < n; i++, data++) {
memcpy(&temp, data, sizeof(temp));
Py_XDECREF(temp);
}
}
}
else { /* 处理不对齐的数据 */
# 如果数组的维度超过了 Legacy 迭代器支持的最大维度(32维)
if (PyArray_NDIM(mp) > NPY_MAXDIMS_LEGACY_ITERS) {
# 抛出运行时错误,说明函数最多支持32维数组
PyErr_Format(PyExc_RuntimeError,
"this function only supports up to 32 dimensions but "
"the array has %d.", PyArray_NDIM(mp));
# 返回错误代码
return -1;
}
# 初始化一个原始迭代器
PyArray_RawIterBaseInit(&it, mp);
# 遍历数组中的每个元素
while(it.index < it.size) {
# 使用临时变量释放当前迭代器指向的对象
memcpy(&temp, it.dataptr, sizeof(temp));
Py_XDECREF(temp);
# 移动迭代器到下一个元素
PyArray_ITER_NEXT(&it);
}
}
# 返回成功代码
return 0;
/*
* 此函数作为一个入口点,确保 `np.empty()` 填充 dtype=object(包括字段)为 `None`,
* 而不是保留为 NULL。因为未显式支持 NULL(尽管 Cython 现在支持了,我们从未严格保证过)。
*
* 假设连续内存布局
*
* TODO: 对于结构体而言,这个函数非常荒谬,应该使用 dtype_traversal 函数来代替...
*/
NPY_NO_EXPORT int
PyArray_SetObjectsToNone(PyArrayObject *arr)
{
// 获取数组的描述符
PyArray_Descr* descr = PyArray_DESCR(arr);
// 非遗留数据类型需要负责初始化其内部引用
if (!NPY_DT_is_legacy(NPY_DTYPE(descr))) {
return 0;
}
npy_intp i,n;
n = PyArray_SIZE(arr);
// 如果数据类型是对象类型(dtype=object)
if (descr->type_num == NPY_OBJECT) {
PyObject **optr;
// optr 指向数组数据的起始位置,这是一个 PyObject 指针数组
optr = (PyObject **)(PyArray_DATA(arr));
for (i = 0; i < n; i++) {
// 增加 Py_None 的引用计数,并将其赋值给当前位置的指针
Py_INCREF(Py_None);
*optr++ = Py_None;
}
}
else {
char *optr;
// optr 指向数组数据的起始位置,这是一个字符指针(字节流)
optr = PyArray_DATA(arr);
for (i = 0; i < n; i++) {
// 根据数据类型描述符填充 optr 指向的数据区域为 None
if (_fill_with_none(optr, descr) < 0) {
return -1;
}
optr += descr->elsize;
}
}
return 0;
}
/*
* 根据数据类型描述符填充 optr 指向的数据区域为 None
*/
static int
_fill_with_none(char *optr, PyArray_Descr *dtype)
{
// 如果数据类型不具有 NPY_ITEM_REFCOUNT 标志,则直接返回
if (!PyDataType_FLAGCHK(dtype, NPY_ITEM_REFCOUNT)) {
return 0;
}
PyObject *None = Py_None;
// 如果数据类型是对象类型(dtype=object)
if (dtype->type_num == NPY_OBJECT) {
// 增加 Py_None 的引用计数,并将其拷贝到 optr 指向的位置
Py_XINCREF(Py_None);
memcpy(optr, &None, sizeof(PyObject *));
}
// 如果数据类型具有字段(结构体)
else if (PyDataType_HASFIELDS(dtype)) {
PyObject *key, *value, *title = NULL;
PyArray_Descr *new;
int offset;
Py_ssize_t pos = 0;
// 遍历字段字典,填充各个字段为 None
while (PyDict_Next(PyDataType_FIELDS(dtype), &pos, &key, &value)) {
if (NPY_TITLE_KEY(key, value)) {
continue; // 忽略标题字段
}
// 解析字段值为新的数据类型描述符、偏移量和标题
if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset, &title)) {
return -1;
}
// 递归调用 _fill_with_none 填充字段数据区域为 None
if (_fill_with_none(optr + offset, new) < 0) {
return -1;
}
}
}
// 如果数据类型具有子数组
else if (PyDataType_HASSUBARRAY(dtype)) {
int size, i, inner_elsize;
// 获取子数组的元素大小
inner_elsize = PyDataType_SUBARRAY(dtype)->base->elsize;
if (inner_elsize == 0) {
/* 没有任何元素,直接返回 */
return 0;
}
// 子数组在内存中是连续的
size = dtype->elsize / inner_elsize;
// 逐个元素递归调用 _fill_with_none
for (i = 0; i < size; i++) {
if (_fill_with_none(optr, PyDataType_SUBARRAY(dtype)->base) < 0) {
return -1;
}
optr += inner_elsize;
}
}
else {
/* 不应该到达的路径,断言错误 */
assert(0);
}
return 0;
}