NumPy 源码解析(六十八)
.\numpy\numpy\_core\src\multiarray\mapping.h
// 外部声明,用于将数组对象视为映射对象的方法集合
extern NPY_NO_EXPORT PyMappingMethods array_as_mapping;
/*
* 用于存储高级(也称为fancy)索引所需信息的对象。
* 不是公共对象,因此原则上不必是Python对象。
*/
} PyArrayMapIterObject;
// 外部声明,定义了PyArrayMapIterObject的类型对象
extern NPY_NO_EXPORT PyTypeObject PyArrayMapIter_Type;
/*
* 结构体,用于解析索引。
* 即整数索引只需解析一次,后续需要验证切片和数组,
* 对于省略号,需要确定其代表的切片数量。
*/
typedef struct {
/*
* 索引对象:切片、数组或NULL。拥有一个引用。
*/
PyObject *object;
/*
* 整数索引的值,省略号代表的切片数量,
* 如果输入是整数数组则为-1,布尔数组的原始大小。
*/
npy_intp value;
/* 索引类型,参见mapping.c中的常量 */
int type;
} npy_index_info;
// 下面是一系列用于数组对象的非公开(NPY_NO_EXPORT)函数声明
// 返回数组对象的长度
NPY_NO_EXPORT Py_ssize_t
array_length(PyArrayObject *self);
// 返回数组对象的第i个元素作为新的数组对象
NPY_NO_EXPORT PyObject *
array_item_asarray(PyArrayObject *self, npy_intp i);
// 返回数组对象的第i个元素作为标量对象
NPY_NO_EXPORT PyObject *
array_item_asscalar(PyArrayObject *self, npy_intp i);
// 返回数组对象的第i个元素
NPY_NO_EXPORT PyObject *
array_item(PyArrayObject *self, Py_ssize_t i);
// 返回数组对象的索引操作结果作为新的数组对象
NPY_NO_EXPORT PyObject *
array_subscript_asarray(PyArrayObject *self, PyObject *op);
// 返回数组对象的索引操作结果
NPY_NO_EXPORT PyObject *
array_subscript(PyArrayObject *self, PyObject *op);
// 对数组对象的第i个元素进行赋值操作
NPY_NO_EXPORT int
array_assign_item(PyArrayObject *self, Py_ssize_t i, PyObject *v);
/*
* 映射调用的原型声明 —— 不属于C-API的一部分,
* 因为只有作为getitem调用的一部分才有用。
*/
// 重置PyArrayMapIterObject对象,准备进行映射迭代
NPY_NO_EXPORT int
PyArray_MapIterReset(PyArrayMapIterObject *mit);
// 将PyArrayMapIterObject对象向前移动一步
NPY_NO_EXPORT void
PyArray_MapIterNext(PyArrayMapIterObject *mit);
// 检查PyArrayMapIterObject对象的索引是否有效
NPY_NO_EXPORT int
PyArray_MapIterCheckIndices(PyArrayMapIterObject *mit);
// 根据PyArrayMapIterObject对象的轴交换映射
NPY_NO_EXPORT void
PyArray_MapIterSwapAxes(PyArrayMapIterObject *mit, PyArrayObject **ret, int getmap);
// 创建新的PyArrayMapIterObject对象,用于处理高级索引
NPY_NO_EXPORT PyObject*
PyArray_MapIterNew(npy_index_info *indices , int index_num, int index_type,
int ndim, int fancy_ndim,
PyArrayObject *arr, PyArrayObject *subspace,
npy_uint32 subspace_iter_flags, npy_uint32 subspace_flags,
npy_uint32 extra_op_flags, PyArrayObject *extra_op,
PyArray_Descr *extra_op_dtype);
// 如果重叠,则在数组a和索引之间复制部分数据
NPY_NO_EXPORT PyObject *
PyArray_MapIterArrayCopyIfOverlap(PyArrayObject * a, PyObject * index,
int copy_if_overlap, PyArrayObject *extra_op);
.\numpy\numpy\_core\src\multiarray\methods.c
/*
* 定义 NPY_NO_DEPRECATED_API 来避免使用已弃用的 NumPy API 版本
* 定义 _MULTIARRAYMODULE 用于多维数组模块
*/
/*
* 清除 PY_SSIZE_T_CLEAN 宏定义,确保 Python.h 中定义 ssize_t
*/
/*
* 引入 NumPy 相关头文件
*/
/*
* 引入 NumPy 内部模块头文件
*/
/*
* 引入其他头文件
*/
/*
* NpyArg_ParseKeywords
*
* 用于不需要 args 参数的情况下提供与 PyArg_ParseTupleAndKeywords 类似的关键字解析功能的实用函数
*/
static int
NpyArg_ParseKeywords(PyObject *keys, const char *format, char **kwlist, ...)
{
PyObject *args = PyTuple_New(0);
int ret;
va_list va;
if (args == NULL) {
PyErr_SetString(PyExc_RuntimeError,
"Failed to allocate new tuple");
return 0;
}
va_start(va, kwlist);
ret = PyArg_VaParseTupleAndKeywords(args, keys, format, kwlist, va);
va_end(va);
Py_DECREF(args);
return ret;
}
/*
* npy_forward_method
*
* 将方法调用转发到 Python 函数,同时添加 self 参数:
* callable(self, ...)
*/
static PyObject *
npy_forward_method(
PyObject *callable, PyObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
PyObject *args_buffer[NPY_MAXARGS];
/* 理论上 NPY_MAXARGS 足够用 */
PyObject **new_args = args_buffer;
/*
* `PY_VECTORCALL_ARGUMENTS_OFFSET` 似乎从未设置,可能 `args[-1]`
* 总是 `self`,但除非 Python 文档中明确说明,不要依赖于此。
*/
npy_intp len_kwargs = kwnames != NULL ? PyTuple_GET_SIZE(kwnames) : 0;
size_t original_arg_size = (len_args + len_kwargs) * sizeof(PyObject *);
if (NPY_UNLIKELY(len_args + len_kwargs > NPY_MAXARGS)) {
new_args = (PyObject **)PyMem_MALLOC(original_arg_size + sizeof(PyObject *));
if (new_args == NULL) {
/*
* 如果分配内存失败,Python 将使用 `PY_VECTORCALL_ARGUMENTS_OFFSET`,
* 我们可能需要为此添加一个快速路径(希望几乎总是)。
*/
return PyErr_NoMemory();
}
}
new_args[0] = self;
memcpy(&new_args[1], args, original_arg_size);
PyObject *res = PyObject_Vectorcall(callable, new_args, len_args+1, kwnames);
if (NPY_UNLIKELY(len_args + len_kwargs > NPY_MAXARGS)) {
PyMem_FREE(new_args);
}
return res;
}
/*
* Forwards an ndarray method to the function numpy._core._methods.<name>(...),
* caching the callable in a local static variable. Note that the
* initialization is not thread-safe, but relies on the CPython GIL to
* be correct.
*/
npy_cache_import( \
"numpy._core._methods",
&npy_thread_unsafe_state.name); \
if (npy_thread_unsafe_state.name == NULL) { \
return NULL; \
} \
return npy_forward_method(npy_thread_unsafe_state.name, \
(PyObject *)self, args, len_args, kwnames)
/*
* Implements the ndarray 'take' method in Python/C API. This method retrieves
* elements from the array based on specified indices along a given axis,
* handling optional parameters like output array, axis, and clipping mode.
*/
static PyObject *
array_take(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
int dimension = NPY_RAVEL_AXIS; // Default axis for flattening
PyObject *indices; // Indices array
PyArrayObject *out = NULL; // Output array
NPY_CLIPMODE mode = NPY_RAISE; // Clipping mode
NPY_PREPARE_ARGPARSER; // Prepares argument parsing context
if (npy_parse_arguments("take", args, len_args, kwnames,
"indices", NULL, &indices,
"|axis", &PyArray_AxisConverter, &dimension,
"|out", &PyArray_OutputConverter, &out,
"|mode", &PyArray_ClipmodeConverter, &mode,
NULL, NULL, NULL) < 0) {
return NULL; // Argument parsing failed
}
PyObject *ret = PyArray_TakeFrom(self, indices, dimension, out, mode);
/* this matches the unpacking behavior of ufuncs */
if (out == NULL) {
return PyArray_Return((PyArrayObject *)ret); // Return as ndarray
}
else {
return ret; // Return directly
}
}
/*
* Implements the ndarray 'fill' method in Python/C API. This method fills
* the array with a scalar value provided as argument.
*/
static PyObject *
array_fill(PyArrayObject *self, PyObject *args)
{
PyObject *obj; // Scalar value to fill with
if (!PyArg_ParseTuple(args, "O:fill", &obj)) {
return NULL; // Parsing argument tuple failed
}
if (PyArray_FillWithScalar(self, obj) < 0) {
return NULL; // Filling array failed
}
Py_RETURN_NONE; // Return None
}
/*
* Implements the ndarray 'put' method in Python/C API. This method puts values
* into the array at specified indices, handling optional parameters like
* values array and clipping mode.
*/
static PyObject *
array_put(PyArrayObject *self, PyObject *args, PyObject *kwds)
{
PyObject *indices, *values; // Indices and values arrays
NPY_CLIPMODE mode = NPY_RAISE; // Clipping mode
static char *kwlist[] = {"indices", "values", "mode", NULL}; // Keyword list
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O&:put", kwlist,
&indices,
&values,
PyArray_ClipmodeConverter, &mode))
return NULL; // Parsing argument tuple failed
return PyArray_PutTo(self, values, indices, mode); // Put values into array
}
/*
* Implements the ndarray 'reshape' method in Python/C API. This method reshapes
* the array according to new dimensions, with optional parameters for order
* and copy mode.
*/
static PyObject *
array_reshape(PyArrayObject *self, PyObject *args, PyObject *kwds)
{
static char *keywords[] = {"order", "copy", NULL}; // Keyword list
PyArray_Dims newshape; // New shape dimensions
PyObject *ret; // Return value
NPY_ORDER order = NPY_CORDER; // Default order
NPY_COPYMODE copy = NPY_COPY_IF_NEEDED; // Default copy mode
Py_ssize_t n = PyTuple_Size(args); // Number of arguments in tuple
// 解析关键字参数 kwds,接受两个可选参数,分别转换为 order 和 copy
if (!NpyArg_ParseKeywords(kwds, "|$O&O&", keywords,
PyArray_OrderConverter, &order,
PyArray_CopyConverter, ©)) {
// 解析失败则返回 NULL
return NULL;
}
// 如果 n 小于等于 1
if (n <= 1) {
// 如果 n 不等于 0 并且 args 中的第一个参数是 Py_None
if (n != 0 && PyTuple_GET_ITEM(args, 0) == Py_None) {
// 返回一个基于 self 的视图(view),无需新的形状和步幅参数
return PyArray_View(self, NULL, NULL);
}
// 如果无法解析 args 为一个整数数组,返回 NULL
if (!PyArg_ParseTuple(args, "O&:reshape", PyArray_IntpConverter,
&newshape)) {
return NULL;
}
}
else {
// 如果 n 大于 1,尝试解析 args 为整数数组 newshape
if (!PyArray_IntpConverter(args, &newshape)) {
// 如果未设置错误信息,则设置类型错误信息
if (!PyErr_Occurred()) {
PyErr_SetString(PyExc_TypeError,
"invalid shape");
}
// 跳转到失败处理块
goto fail;
}
}
// 调用 _reshape_with_copy_arg 函数进行数组重塑,返回结果给 ret
ret = _reshape_with_copy_arg(self, &newshape, order, copy);
// 释放 newshape 中的缓存对象
npy_free_cache_dim_obj(newshape);
// 返回重塑后的结果 ret
return ret;
fail:
// 失败时释放 newshape 中的缓存对象,返回 NULL
npy_free_cache_dim_obj(newshape);
return NULL;
static PyObject *
array_squeeze(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
PyObject *axis_in = NULL; // 定义用于接收轴参数的变量
npy_bool axis_flags[NPY_MAXDIMS]; // 定义用于存储轴标志的数组
NPY_PREPARE_ARGPARSER; // 宏,准备参数解析器
if (npy_parse_arguments("squeeze", args, len_args, kwnames,
"|axis", NULL, &axis_in, // 解析参数中的可选轴参数
NULL, NULL, NULL) < 0) { // 如果解析失败,返回空
return NULL;
}
if (axis_in == NULL || axis_in == Py_None) { // 如果未指定轴参数或者为None
return PyArray_Squeeze(self); // 调用NumPy函数去除数组中的单维度
}
else {
if (PyArray_ConvertMultiAxis(axis_in, PyArray_NDIM(self),
axis_flags) != NPY_SUCCEED) {
return NULL; // 如果无法转换多个轴参数,返回空
}
return PyArray_SqueezeSelected(self, axis_flags); // 根据指定的轴参数去除数组中的单维度
}
}
static PyObject *
array_view(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
PyObject *out_dtype = NULL; // 用于接收dtype参数的变量
PyObject *out_type = NULL; // 用于接收type参数的变量
PyArray_Descr *dtype = NULL; // NumPy数组描述符指针
NPY_PREPARE_ARGPARSER; // 宏,准备参数解析器
if (npy_parse_arguments("view", args, len_args, kwnames,
"|dtype", NULL, &out_dtype, // 解析参数中的可选dtype参数
"|type", NULL, &out_type, // 解析参数中的可选type参数
NULL, NULL, NULL) < 0) { // 如果解析失败,返回空
return NULL;
}
/* If user specified a positional argument, guess whether it
represents a type or a dtype for backward compatibility. */
if (out_dtype) { // 如果指定了dtype参数
/* type specified? */
if (PyType_Check(out_dtype) &&
PyType_IsSubtype((PyTypeObject *)out_dtype,
&PyArray_Type)) { // 如果dtype是有效的NumPy数组子类
if (out_type) { // 如果同时指定了type参数,报错
PyErr_SetString(PyExc_ValueError,
"Cannot specify output type twice.");
return NULL;
}
out_type = out_dtype; // 将dtype参数赋给type参数
out_dtype = NULL; // 清空dtype参数
}
}
if ((out_type) && (!PyType_Check(out_type) ||
!PyType_IsSubtype((PyTypeObject *)out_type,
&PyArray_Type))) {
PyErr_SetString(PyExc_ValueError,
"Type must be a sub-type of ndarray type");
return NULL; // 如果指定的type参数不是有效的NumPy数组子类,报错
}
if ((out_dtype) &&
(PyArray_DescrConverter(out_dtype, &dtype) == NPY_FAIL)) {
return NULL; // 如果无法将dtype参数转换为NumPy数组描述符,返回空
}
return PyArray_View(self, dtype, (PyTypeObject*)out_type); // 返回数组的视图对象
}
static PyObject *
array_argmax(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
int axis = NPY_RAVEL_AXIS; // 轴的默认值
PyArrayObject *out = NULL; // 输出数组的指针
npy_bool keepdims = NPY_FALSE; // 是否保持维度标志
NPY_PREPARE_ARGPARSER; // 宏,准备参数解析器
if (npy_parse_arguments("argmax", args, len_args, kwnames,
"|axis", &PyArray_AxisConverter, &axis, // 解析可选的轴参数
"|out", &PyArray_OutputConverter, &out, // 解析可选的输出参数
"$keepdims", &PyArray_BoolConverter, &keepdims, // 解析可选的keepdims参数
NULL, NULL, NULL) < 0) {
return NULL; // 如果解析失败,返回空
}
PyObject *ret = _PyArray_ArgMaxWithKeepdims(self, axis, out, keepdims);
/* this matches the unpacking behavior of ufuncs */
// 这与ufunc的解包行为相匹配,暂无其他注释
if (out == NULL) {
return PyArray_Return((PyArrayObject *)ret);
}
else {
return ret;
}
static PyObject *
array_argmin(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
// 设置默认的轴为扁平化后的轴
int axis = NPY_RAVEL_AXIS;
// 输出数组对象初始化为空
PyArrayObject *out = NULL;
// 是否保持维度参数初始化为假
npy_bool keepdims = NPY_FALSE;
// 准备解析参数
NPY_PREPARE_ARGPARSER;
// 解析参数,根据结果进行相应处理
if (npy_parse_arguments("argmin", args, len_args, kwnames,
"|axis", &PyArray_AxisConverter, &axis,
"|out", &PyArray_OutputConverter, &out,
"$keepdims", &PyArray_BoolConverter, &keepdims,
NULL, NULL, NULL) < 0) {
// 解析失败,返回空指针
return NULL;
}
// 调用具体的函数计算最小值的索引
PyObject *ret = _PyArray_ArgMinWithKeepdims(self, axis, out, keepdims);
/* this matches the unpacking behavior of ufuncs */
// 根据输出情况选择返回结果
if (out == NULL) {
// 如果输出为空,则转换为数组对象并返回
return PyArray_Return((PyArrayObject *)ret);
}
else {
// 否则直接返回结果对象
return ret;
}
}
static PyObject *
array_max(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
// 转发到 _amax 函数处理
NPY_FORWARD_NDARRAY_METHOD(_amax);
}
static PyObject *
array_min(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
// 转发到 _amin 函数处理
NPY_FORWARD_NDARRAY_METHOD(_amin);
}
static PyObject *
array_swapaxes(PyArrayObject *self, PyObject *args)
{
// 定义两个轴变量
int axis1, axis2;
// 解析传入的参数元组,获取两个轴的值
if (!PyArg_ParseTuple(args, "ii:swapaxes", &axis1, &axis2)) {
// 解析失败,返回空指针
return NULL;
}
// 调用 NumPy 库函数交换数组轴
return PyArray_SwapAxes(self, axis1, axis2);
}
/*NUMPY_API
从数组的每个元素中获取字节的子集
typed 参数的引用被窃取,不得为空
*/
NPY_NO_EXPORT PyObject *
PyArray_GetField(PyArrayObject *self, PyArray_Descr *typed, int offset)
{
PyObject *ret = NULL;
PyObject *safe;
int self_elsize, typed_elsize;
// 检查 self 是否为空
if (self == NULL) {
// 设置错误信息并返回空指针
PyErr_SetString(PyExc_ValueError,
"self is NULL in PyArray_GetField");
return NULL;
}
// 检查 typed 是否为空
if (typed == NULL) {
// 设置错误信息并返回空指针
PyErr_SetString(PyExc_ValueError,
"typed is NULL in PyArray_GetField");
return NULL;
}
/* 检查是否重新解释包含对象的内存 */
if (_may_have_objects(PyArray_DESCR(self)) || _may_have_objects(typed)) {
// 导入线程安全状态
npy_cache_import("numpy._core._internal", "_getfield_is_safe",
&npy_thread_unsafe_state._getfield_is_safe);
// 检查线程安全状态是否为 NULL
if (npy_thread_unsafe_state._getfield_is_safe == NULL) {
// 释放 typed 并返回空指针
Py_DECREF(typed);
return NULL;
}
/* 只返回 True 或抛出异常 */
// 调用 _getfield_is_safe 函数进行安全性检查
safe = PyObject_CallFunction(npy_thread_unsafe_state._getfield_is_safe,
"OOi", PyArray_DESCR(self),
typed, offset);
// 检查安全性检查返回值是否为空
if (safe == NULL) {
// 释放 typed 并返回空指针
Py_DECREF(typed);
return NULL;
}
// 释放 safe 对象引用
Py_DECREF(safe);
}
// 获取 self 和 typed 的元素大小
self_elsize = PyArray_ITEMSIZE(self);
typed_elsize = typed->elsize;
/* 检查值是否有效 */
// 继续执行后续操作
if (typed_elsize > self_elsize) {
PyErr_SetString(PyExc_ValueError, "new type is larger than original type");
Py_DECREF(typed);
return NULL;
}
if (offset < 0) {
PyErr_SetString(PyExc_ValueError, "offset is negative");
Py_DECREF(typed);
return NULL;
}
if (offset > self_elsize - typed_elsize) {
PyErr_SetString(PyExc_ValueError, "new type plus offset is larger than original type");
Py_DECREF(typed);
return NULL;
}
ret = PyArray_NewFromDescr_int(
Py_TYPE(self), typed,
PyArray_NDIM(self), PyArray_DIMS(self), PyArray_STRIDES(self),
PyArray_BYTES(self) + offset,
PyArray_FLAGS(self) & ~NPY_ARRAY_F_CONTIGUOUS,
(PyObject *)self, (PyObject *)self,
_NPY_ARRAY_ALLOW_EMPTY_STRING);
return ret;
/*NUMPY_API*/
NPY_NO_EXPORT PyObject *
PyArray_Byteswap(PyArrayObject *self, npy_bool inplace)
{
PyArrayObject *ret; // 定义一个 PyArrayObject 指针 ret
npy_intp size; // 定义一个数组大小的整数型变量 size
PyArray_CopySwapNFunc *copyswapn; // 定义一个指向 PyArray_CopySwapNFunc 函数的指针 copyswapn
PyArrayIterObject *it; // 定义一个 PyArrayIterObject 迭代器对象指针 it
// 获取数组的拷贝和交换函数,并赋给 copyswapn
copyswapn = PyDataType_GetArrFuncs(PyArray_DESCR(self))->copyswapn;
if (inplace) {
if (PyArray_FailUnlessWriteable(self, "array to be byte-swapped") < 0) {
return NULL;
}
size = PyArray_SIZE(self);
if (PyArray_ISONESEGMENT(self)) {
copyswapn(PyArray_DATA(self), PyArray_ITEMSIZE(self), NULL, -1, size, 1, self);
}
else { /* 使用迭代器 */
int axis = -1;
npy_intp stride;
it = (PyArrayIterObject *) \
PyArray_IterAllButAxis((PyObject *)self, &axis);
stride = PyArray_STRIDES(self)[axis];
size = PyArray_DIMS(self)[axis];
while (it->index < it->size) {
copyswapn(it->dataptr, stride, NULL, -1, size, 1, self);
PyArray_ITER_NEXT(it);
}
Py_DECREF(it);
}
Py_INCREF(self);
return (PyObject *)self;
}
else {
PyObject *new;
if ((ret = (PyArrayObject *)PyArray_NewCopy(self,-1)) == NULL) {
return NULL;
}
new = PyArray_Byteswap(ret, NPY_TRUE);
Py_DECREF(new);
return (PyObject *)ret;
}
static PyObject *
array_tofile(PyArrayObject *self, PyObject *args, PyObject *kwds)
{
int own;
PyObject *file;
char *sep = "";
char *format = "";
static char *kwlist[] = {"file", "sep", "format", NULL};
// 解析传入的参数,其中file是必选参数,sep和format是可选参数,默认为空字符串
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|ss:tofile", kwlist,
&file,
&sep,
&format)) {
return NULL;
}
// 将file对象转换为文件系统路径对象
file = NpyPath_PathlikeToFspath(file);
if (file == NULL) {
return NULL;
}
// 检查file对象是否为字节对象或Unicode对象,若是则尝试以"wb"模式打开文件
if (PyBytes_Check(file) || PyUnicode_Check(file)) {
// 使用npy_PyFile_OpenFile函数打开文件,返回的文件对象赋值给file变量
Py_SETREF(file, npy_PyFile_OpenFile(file, "wb"));
if (file == NULL) {
return NULL;
}
own = 1; // 设置own为1,表示需要管理文件对象的生命周期
}
else {
own = 0; // 文件对象的生命周期由调用者管理
}
int file_ret = PyArray_ToFileObject(self, file, sep, format);
int close_ret = 0;
if (own) {
// 保存当前的错误类型、错误值和错误回溯信息
PyObject *err_type, *err_value, *err_traceback;
PyErr_Fetch(&err_type, &err_value, &err_traceback);
// 调用 NumPy 的函数关闭文件,更新关闭文件的返回值
close_ret = npy_PyFile_CloseFile(file);
// 将之前保存的错误类型、错误值和错误回溯信息恢复并抛出异常
npy_PyErr_ChainExceptions(err_type, err_value, err_traceback);
}
// 减少文件对象的引用计数,释放其内存
Py_DECREF(file);
// 如果写入文件操作或者关闭文件操作中有任何一个失败,则返回空值对象
if (file_ret || close_ret) {
return NULL;
}
// 操作成功完成,返回空值对象
Py_RETURN_NONE;
static PyObject *
array_toscalar(PyArrayObject *self, PyObject *args)
{
// 定义一个多维数组索引数组
npy_intp multi_index[NPY_MAXDIMS];
// 获取参数元组的大小
int n = PyTuple_GET_SIZE(args);
// 获取数组的维度数
int idim, ndim = PyArray_NDIM(self);
/* 如果参数数量为1且第一个参数是元组,则将参数指向该元组 */
if (n == 1 && PyTuple_Check(PyTuple_GET_ITEM(args, 0))) {
args = PyTuple_GET_ITEM(args, 0);
n = PyTuple_GET_SIZE(args);
}
// 如果参数数量为0
if (n == 0) {
// 如果数组大小为1,将多维数组索引全部设为0
if (PyArray_SIZE(self) == 1) {
for (idim = 0; idim < ndim; ++idim) {
multi_index[idim] = 0;
}
}
// 否则,抛出值错误异常,说明只能将大小为1的数组转换为标量
else {
PyErr_SetString(PyExc_ValueError,
"can only convert an array of size 1 to a Python scalar");
return NULL;
}
}
// 如果参数数量为1且数组维度数不为1,处理C顺序的平铺索引
else if (n == 1 && ndim != 1) {
// 获取数组形状和大小
npy_intp *shape = PyArray_SHAPE(self);
npy_intp value, size = PyArray_SIZE(self);
// 将第一个参数转换为整数索引
value = PyArray_PyIntAsIntp(PyTuple_GET_ITEM(args, 0));
if (error_converting(value)) {
return NULL;
}
// 检查并调整索引值
if (check_and_adjust_index(&value, size, -1, NULL) < 0) {
return NULL;
}
/* 将平铺索引转换为多维索引 */
for (idim = ndim-1; idim >= 0; --idim) {
multi_index[idim] = value % shape[idim];
value /= shape[idim];
}
}
// 如果参数数量等于数组维度数,处理多维索引元组
else if (n == ndim) {
npy_intp value;
for (idim = 0; idim < ndim; ++idim) {
// 将每个参数转换为整数索引
value = PyArray_PyIntAsIntp(PyTuple_GET_ITEM(args, idim));
if (error_converting(value)) {
return NULL;
}
multi_index[idim] = value;
}
}
// 参数数量与数组维度数不符,抛出值错误异常
else {
PyErr_SetString(PyExc_ValueError,
"incorrect number of indices for array");
return NULL;
}
// 返回数组指定多维索引的元素
return PyArray_MultiIndexGetItem(self, multi_index);
}
static PyObject *
array_astype(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
/*
* TODO: UNSAFE default for compatibility, I think
* switching to SAME_KIND by default would be good.
*/
// 数据类型信息结构体,默认使用UNSAFE类型转换
npy_dtype_info dt_info = {NULL, NULL};
NPY_CASTING casting = NPY_UNSAFE_CASTING;
NPY_ORDER order = NPY_KEEPORDER;
NPY_ASTYPECOPYMODE forcecopy = 1;
int subok = 1;
// 准备解析器参数
NPY_PREPARE_ARGPARSER;
// 解析函数参数
if (npy_parse_arguments("astype", args, len_args, kwnames,
// 解析dtype参数
"dtype", &PyArray_DTypeOrDescrConverterRequired, &dt_info,
// 解析order参数
"|order", &PyArray_OrderConverter, &order,
// 解析casting参数
"|casting", &PyArray_CastingConverter, &casting,
// 解析subok参数
"|subok", &PyArray_PythonPyIntFromInt, &subok,
// 解析copy参数
"|copy", &PyArray_AsTypeCopyConverter, &forcecopy,
NULL, NULL, NULL) < 0) {
// 解析失败时释放内存并返回空指针
Py_XDECREF(dt_info.descr);
Py_XDECREF(dt_info.dtype);
return NULL;
}
/* 如果不是具体的dtype实例,则为数组找到最佳的dtype实例 */
// (此处未提供完整代码)
}
// 定义一个指向 PyArray_Descr 结构体的指针变量
PyArray_Descr *dtype;
// 调用 PyArray_AdaptDescriptorToArray 函数,将 self 对象适配为描述符数组,返回描述符指针给 dtype,并释放 dt_info.descr 引用计数
dtype = PyArray_AdaptDescriptorToArray(self, dt_info.dtype, dt_info.descr);
Py_XDECREF(dt_info.descr); // 释放 dt_info.descr 的引用计数
Py_DECREF(dt_info.dtype); // 释放 dt_info.dtype 的引用计数
if (dtype == NULL) { // 如果 dtype 为空,则返回空指针
return NULL;
}
/*
* 如果内存布局匹配,并且数据类型等效,
* 当 subok 为 False 时不是子类型,
* 如果转换允许视图,则可以跳过复制。
*/
if (forcecopy != NPY_AS_TYPE_COPY_ALWAYS && // 如果不是强制复制
(order == NPY_KEEPORDER || // 保持原序
(order == NPY_ANYORDER && // 任意顺序
(PyArray_IS_C_CONTIGUOUS(self) || // 是 C 连续数组
PyArray_IS_F_CONTIGUOUS(self))) || // 是 Fortran 连续数组
(order == NPY_CORDER && // C 顺序
PyArray_IS_C_CONTIGUOUS(self)) || // 是 C 连续数组
(order == NPY_FORTRANORDER && // Fortran 顺序
PyArray_IS_F_CONTIGUOUS(self))) && // 是 Fortran 连续数组
(subok || PyArray_CheckExact(self))) { // 如果是子类型允许或者精确匹配 self
npy_intp view_offset;
npy_intp is_safe = PyArray_SafeCast(dtype, PyArray_DESCR(self),
&view_offset, NPY_NO_CASTING, 1); // 安全地进行类型转换,并获取视图偏移量
if (is_safe && (view_offset != NPY_MIN_INTP)) { // 如果转换安全且视图偏移量不是最小整数值
Py_DECREF(dtype); // 释放 dtype 的引用计数
Py_INCREF(self); // 增加 self 的引用计数
return (PyObject *)self; // 返回 self 对象的 Python 对象
}
}
// 如果无法将 self 转换为 dtype 所需的类型,则设置类型转换错误并返回空指针
if (!PyArray_CanCastArrayTo(self, dtype, casting)) {
PyErr_Clear(); // 清除当前异常状态
npy_set_invalid_cast_error(
PyArray_DESCR(self), dtype, casting, PyArray_NDIM(self) == 0); // 设置无效类型转换错误
Py_DECREF(dtype); // 释放 dtype 的引用计数
return NULL;
}
PyArrayObject *ret; // 定义 PyArrayObject 结构体指针变量 ret
/* This steals the reference to dtype */
Py_INCREF(dtype); // 增加 dtype 的引用计数
ret = (PyArrayObject *)PyArray_NewLikeArray(
self, order, dtype, subok); // 创建一个类似 self 的新数组 ret,使用 order、dtype 和 subok 参数
if (ret == NULL) { // 如果创建失败,则释放 dtype 的引用计数并返回空指针
Py_DECREF(dtype); // 释放 dtype 的引用计数
return NULL;
}
// 减少维度数,再次删除子数组维度
int out_ndim = PyArray_NDIM(ret); // 获取 ret 的维度数
PyArray_Descr *out_descr = PyArray_DESCR(ret); // 获取 ret 的描述符
if (out_ndim != PyArray_NDIM(self)) { // 如果 ret 的维度数不等于 self 的维度数
((PyArrayObject_fields *)ret)->nd = PyArray_NDIM(self); // 设置 ret 的维度数为 self 的维度数
((PyArrayObject_fields *)ret)->descr = dtype; // 设置 ret 的描述符为 dtype
}
int success = PyArray_CopyInto(ret, self); // 将 self 复制到 ret 中
Py_DECREF(dtype); // 释放 dtype 的引用计数
((PyArrayObject_fields *)ret)->nd = out_ndim; // 恢复 ret 的维度数
((PyArrayObject_fields *)ret)->descr = out_descr; // 恢复 ret 的描述符
if (success < 0) { // 如果复制失败,则释放 ret 并返回空指针
Py_DECREF(ret); // 释放 ret 的引用计数
return NULL;
}
return (PyObject *)ret; // 返回 ret 的 Python 对象
/* 默认子类型实现 */
static PyObject *
array_finalizearray(PyArrayObject *self, PyObject *obj)
{
/* 返回 None 对象,表示无需特殊处理 */
Py_RETURN_NONE;
}
static PyObject *
array_wraparray(PyArrayObject *self, PyObject *args)
{
PyArrayObject *arr;
PyObject *obj;
/* 检查参数个数,只接受一个参数 */
if (PyTuple_Size(args) < 1) {
PyErr_SetString(PyExc_TypeError,
"only accepts 1 argument");
return NULL;
}
obj = PyTuple_GET_ITEM(args, 0);
if (obj == NULL) {
return NULL;
}
/* 检查参数是否为 ndarray 对象 */
if (!PyArray_Check(obj)) {
PyErr_SetString(PyExc_TypeError,
"can only be called with ndarray object");
return NULL;
}
arr = (PyArrayObject *)obj;
/* 如果 self 和 arr 的类型不同 */
if (Py_TYPE(self) != Py_TYPE(arr)) {
/* 获取 arr 的描述符 */
PyArray_Descr *dtype = PyArray_DESCR(arr);
Py_INCREF(dtype);
/* 创建一个新的 ndarray 对象,以 arr 作为基础 */
return PyArray_NewFromDescrAndBase(
Py_TYPE(self),
dtype,
PyArray_NDIM(arr),
PyArray_DIMS(arr),
PyArray_STRIDES(arr), PyArray_DATA(arr),
PyArray_FLAGS(arr), (PyObject *)self, obj);
}
else {
/*
* 例如,当从 Python 调用时,类型可能已经正确。
* 典型的 ufunc 路径之前通过 __array_prepare__ 到达此处。
*/
Py_INCREF(arr);
return (PyObject *)arr;
}
}
static PyObject *
array_getarray(PyArrayObject *self, PyObject *args, PyObject *kwds)
{
PyArray_Descr *newtype = NULL;
NPY_COPYMODE copy = NPY_COPY_IF_NEEDED;
static char *kwlist[] = {"dtype", "copy", NULL};
PyObject *ret;
/* 解析参数,接受 dtype 和 copy 作为可选参数 */
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&$O&:__array__", kwlist,
PyArray_DescrConverter, &newtype,
PyArray_CopyConverter, ©)) {
Py_XDECREF(newtype);
return NULL;
}
/* 如果 self 不是精确的 PyArray_Type */
if (!PyArray_CheckExact(self)) {
PyArrayObject *new;
/* 增加对 self 的描述符的引用计数 */
Py_INCREF(PyArray_DESCR(self));
/* 从描述符和 self 创建一个新的 ndarray 对象 */
new = (PyArrayObject *)PyArray_NewFromDescrAndBase(
&PyArray_Type,
PyArray_DESCR(self),
PyArray_NDIM(self),
PyArray_DIMS(self),
PyArray_STRIDES(self),
PyArray_DATA(self),
PyArray_FLAGS(self),
NULL,
(PyObject *)self
);
if (new == NULL) {
return NULL;
}
self = new;
}
else {
Py_INCREF(self);
}
/* 如果需要复制数组数据 */
if (copy == NPY_COPY_ALWAYS) {
/* 如果未提供 newtype,则使用 self 的描述符 */
if (newtype == NULL) {
newtype = PyArray_DESCR(self);
}
/* 将 self 转换为指定类型的 ndarray */
ret = PyArray_CastToType(self, newtype, 0);
Py_DECREF(self);
return ret;
} else { // copy == NPY_COPY_IF_NEEDED || copy == NPY_COPY_NEVER
// 如果 copy 参数是 NPY_COPY_IF_NEEDED 或者 NPY_COPY_NEVER
if (newtype == NULL || PyArray_EquivTypes(PyArray_DESCR(self), newtype)) {
// 如果 newtype 为 NULL 或者 self 的类型等效于 newtype 的类型,返回 self 对象的新引用
return (PyObject *)self;
}
if (copy == NPY_COPY_IF_NEEDED) {
// 如果需要复制,将 self 强制转换为 newtype 类型的数组
ret = PyArray_CastToType(self, newtype, 0);
// 减少 self 的引用计数
Py_DECREF(self);
// 返回转换后的新数组对象
return ret;
} else { // copy == NPY_COPY_NEVER
// 如果不允许复制,设置异常为 ValueError,指定错误消息为 npy_no_copy_err_msg
PyErr_SetString(PyExc_ValueError, npy_no_copy_err_msg);
// 减少 self 的引用计数
Py_DECREF(self);
// 返回空指针,表示出错
return NULL;
}
}
/*
* 检查输入和输出参数中是否有任何非默认的 __array_ufunc__ 方法。
* 如果有,则返回 1;如果没有,则返回 0;如果发生错误,则返回 -1。
*
* 此函数的主要作用是帮助 ndarray.__array_ufunc__ 确定是否可以支持一个 ufunc
* (只有当没有操作数有重写时才是这样)。因此,与 umath/override.c 中不同,
* 实际的重写方法并不需要,一旦找到一个重写方法就可以停止查找。
*/
static int
any_array_ufunc_overrides(PyObject *args, PyObject *kwds)
{
int i;
int nin, nout;
PyObject *out_kwd_obj;
PyObject *fast;
PyObject **in_objs, **out_objs, *where_obj;
/* 检查输入参数 */
nin = PyTuple_Size(args);
if (nin < 0) {
return -1;
}
fast = PySequence_Fast(args, "Could not convert object to sequence");
if (fast == NULL) {
return -1;
}
in_objs = PySequence_Fast_ITEMS(fast);
for (i = 0; i < nin; ++i) {
if (PyUFunc_HasOverride(in_objs[i])) {
Py_DECREF(fast);
return 1;
}
}
Py_DECREF(fast);
/* 如果没有关键字参数,直接返回 0 */
if (kwds == NULL) {
return 0;
}
/* 检查输出参数 */
nout = PyUFuncOverride_GetOutObjects(kwds, &out_kwd_obj, &out_objs);
if (nout < 0) {
return -1;
}
for (i = 0; i < nout; i++) {
if (PyUFunc_HasOverride(out_objs[i])) {
Py_DECREF(out_kwd_obj);
return 1;
}
}
Py_DECREF(out_kwd_obj);
/* 检查 where 参数是否存在 */
where_obj = PyDict_GetItemWithError(kwds, npy_interned_str.where);
if (where_obj == NULL) {
if (PyErr_Occurred()) {
return -1;
}
} else {
if (PyUFunc_HasOverride(where_obj)){
return 1;
}
}
return 0;
}
/*
* ndarray 对象的 __array_ufunc__ 方法的实现。
*/
NPY_NO_EXPORT PyObject *
array_ufunc(PyArrayObject *NPY_UNUSED(self), PyObject *args, PyObject *kwds)
{
PyObject *ufunc, *method_name, *normal_args, *ufunc_method;
PyObject *result = NULL;
int has_override;
assert(PyTuple_CheckExact(args));
assert(kwds == NULL || PyDict_CheckExact(kwds));
/* 至少需要两个参数才能调用 __array_ufunc__ */
if (PyTuple_GET_SIZE(args) < 2) {
PyErr_SetString(PyExc_TypeError,
"__array_ufunc__ requires at least 2 arguments");
return NULL;
}
/* 提取普通参数(除了第一个和第二个参数以外的参数) */
normal_args = PyTuple_GetSlice(args, 2, PyTuple_GET_SIZE(args));
if (normal_args == NULL) {
return NULL;
}
/* 检查是否有重写方法 */
has_override = any_array_ufunc_overrides(normal_args, kwds);
if (has_override < 0) {
goto cleanup;
}
else if (has_override) {
result = Py_NotImplemented;
Py_INCREF(Py_NotImplemented);
goto cleanup;
}
/* 获取第一个参数(ufunc 对象)和第二个参数(方法名) */
ufunc = PyTuple_GET_ITEM(args, 0);
method_name = PyTuple_GET_ITEM(args, 1);
/*
* TODO(?): 在稍后的某个时刻调用 UFunc 代码,
* 因为这里的参数已经被标准化,我们不必再查找 __array_ufunc__。
*/
// 获取ufunc对象的方法method_name,并赋值给ufunc_method变量
ufunc_method = PyObject_GetAttr(ufunc, method_name);
// 如果获取方法失败,跳转到cleanup标签执行清理操作
if (ufunc_method == NULL) {
goto cleanup;
}
// 调用ufunc_method表示的方法,传入normal_args和kwds参数,并将结果赋值给result变量
result = PyObject_Call(ufunc_method, normal_args, kwds);
// 减少ufunc_method对象的引用计数,可能会释放该对象
Py_DECREF(ufunc_method);
cleanup:
Py_DECREF(normal_args);
/* 对 normal_args 进行 DECREF,减少其引用计数 */
/* ufunc 和 method_name 是 borrowed references,无需进行 DECREF */
return result;
}
static PyObject *
array_function(PyArrayObject *NPY_UNUSED(self), PyObject *c_args, PyObject *c_kwds)
{
PyObject *func, *types, *args, *kwargs, *result;
static char *kwlist[] = {"func", "types", "args", "kwargs", NULL};
// 解析传入的参数列表 c_args 和 c_kwds
if (!PyArg_ParseTupleAndKeywords(
c_args, c_kwds, "OOOO:__array_function__", kwlist,
&func, &types, &args, &kwargs)) {
return NULL;
}
// 快速创建 types 的 Python 序列对象,如果失败则返回 NULL
types = PySequence_Fast(
types,
"types argument to ndarray.__array_function__ must be iterable");
if (types == NULL) {
return NULL;
}
// 调用 array_function_method_impl 函数处理函数调用逻辑
result = array_function_method_impl(func, types, args, kwargs);
// 减少 types 对象的引用计数
Py_DECREF(types);
return result;
}
static PyObject *
array_copy(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
NPY_ORDER order = NPY_CORDER;
NPY_PREPARE_ARGPARSER;
// 解析参数,设置拷贝的顺序 order
if (npy_parse_arguments("copy", args, len_args, kwnames,
"|order", PyArray_OrderConverter, &order,
NULL, NULL, NULL) < 0) {
return NULL;
}
// 创建并返回一个新的数组拷贝对象
return PyArray_NewCopy(self, order);
}
/* Separate from array_copy to make __copy__ preserve Fortran contiguity. */
static PyObject *
array_copy_keeporder(PyArrayObject *self, PyObject *args)
{
// 解析参数,确认函数被正确调用
if (!PyArg_ParseTuple(args, ":__copy__")) {
return NULL;
}
// 创建并返回一个新的数组拷贝对象,保留 Fortran 的连续性顺序
return PyArray_NewCopy(self, NPY_KEEPORDER);
}
static PyObject *
array_resize(PyArrayObject *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"refcheck", NULL};
Py_ssize_t size = PyTuple_Size(args);
int refcheck = 1;
PyArray_Dims newshape;
PyObject *ret, *obj;
// 解析关键字参数,设置 refcheck 标志位
if (!NpyArg_ParseKeywords(kwds, "|i", kwlist, &refcheck)) {
return NULL;
}
// 如果没有传入参数则返回 None
if (size == 0) {
Py_RETURN_NONE;
}
else if (size == 1) {
obj = PyTuple_GET_ITEM(args, 0);
// 如果参数是 None 则返回 None
if (obj == Py_None) {
Py_RETURN_NONE;
}
// 否则将 obj 赋值给 args,准备后续处理
args = obj;
}
// 解析并验证参数 args,设置新的数组形状 newshape
if (!PyArray_IntpConverter(args, &newshape)) {
if (!PyErr_Occurred()) {
PyErr_SetString(PyExc_TypeError, "invalid shape");
}
return NULL;
}
// 调整数组 self 到新的形状 newshape,并返回结果
ret = PyArray_Resize(self, &newshape, refcheck, NPY_ANYORDER);
npy_free_cache_dim_obj(newshape);
if (ret == NULL) {
return NULL;
}
// 减少返回结果的引用计数,返回 None
Py_DECREF(ret);
Py_RETURN_NONE;
}
static PyObject *
array_repeat(PyArrayObject *self, PyObject *args, PyObject *kwds) {
PyObject *repeats;
int axis = NPY_RAVEL_AXIS;
static char *kwlist[] = {"repeats", "axis", NULL};
// 解析参数并设置重复次数 repeats 和轴 axis
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&:repeat", kwlist,
&repeats,
PyArray_AxisConverter, &axis)) {
return NULL;
}
// 调用 PyArray_Repeat 函数进行数组重复操作,返回结果作为 PyArrayObject 对象
return PyArray_Return((PyArrayObject *)PyArray_Repeat(self, repeats, axis));
}
static PyObject *
array_choose(PyArrayObject *self, PyObject *args, PyObject *kwds)
{
// 定义关键字列表
static char *keywords[] = {"out", "mode", NULL};
// 初始化变量
PyObject *choices;
PyArrayObject *out = NULL;
NPY_CLIPMODE clipmode = NPY_RAISE;
// 获取参数元组的长度
Py_ssize_t n = PyTuple_Size(args);
// 根据参数个数决定如何解析参数
if (n <= 1) {
// 如果参数个数少于等于1,解析单一参数
if (!PyArg_ParseTuple(args, "O:choose", &choices)) {
return NULL;
}
}
else {
// 否则直接使用参数元组作为选择参数
choices = args;
}
// 解析关键字参数,设置输出对象和裁剪模式
if (!NpyArg_ParseKeywords(kwds, "|O&O&", keywords,
PyArray_OutputConverter, &out,
PyArray_ClipmodeConverter, &clipmode)) {
return NULL;
}
// 调用选择函数,返回结果对象
PyObject *ret = PyArray_Choose(self, choices, out, clipmode);
/* this matches the unpacking behavior of ufuncs */
// 根据输出对象是否为空决定返回值类型
if (out == NULL) {
return PyArray_Return((PyArrayObject *)ret);
}
else {
return ret;
}
}
static PyObject *
array_sort(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
// 初始化变量
int axis = -1;
int val;
NPY_SORTKIND sortkind = _NPY_SORT_UNDEFINED;
PyObject *order = NULL;
PyArray_Descr *saved = NULL;
PyArray_Descr *newd;
int stable = -1;
NPY_PREPARE_ARGPARSER;
// 解析函数参数
if (npy_parse_arguments("sort", args, len_args, kwnames,
"|axis", &PyArray_PythonPyIntFromInt, &axis,
"|kind", &PyArray_SortkindConverter, &sortkind,
"|order", NULL, &order,
"$stable", &PyArray_OptionalBoolConverter, &stable,
NULL, NULL, NULL) < 0) {
return NULL;
}
// 处理特殊情况:当order参数为None时,将其设为NULL
if (order == Py_None) {
order = NULL;
}
// 如果指定了order参数,进行额外处理
if (order != NULL) {
PyObject *new_name;
PyObject *_numpy_internal;
saved = PyArray_DESCR(self);
// 如果数组没有字段,不能指定order
if (!PyDataType_HASFIELDS(saved)) {
PyErr_SetString(PyExc_ValueError, "Cannot specify " \
"order when the array has no fields.");
return NULL;
}
// 导入内部模块_numpy_internal
_numpy_internal = PyImport_ImportModule("numpy._core._internal");
if (_numpy_internal == NULL) {
return NULL;
}
// 调用_numpy_internal模块的方法_newnames
new_name = PyObject_CallMethod(_numpy_internal, "_newnames",
"OO", saved, order);
Py_DECREF(_numpy_internal);
if (new_name == NULL) {
return NULL;
}
// 创建新的描述符对象
newd = PyArray_DescrNew(saved);
if (newd == NULL) {
Py_DECREF(new_name);
return NULL;
}
// 替换描述符对象的字段名
Py_DECREF(((_PyArray_LegacyDescr *)newd)->names);
((_PyArray_LegacyDescr *)newd)->names = new_name;
// 更新数组的描述符对象
((PyArrayObject_fields *)self)->descr = newd;
}
// 检查sortkind和stable参数的合法性
if (sortkind != _NPY_SORT_UNDEFINED && stable != -1) {
PyErr_SetString(PyExc_ValueError,
"`kind` and `stable` parameters can't be provided at "
"the same time. Use only one of them.");
return NULL;
}
else if ((sortkind == _NPY_SORT_UNDEFINED && stable == -1) || (stable == 0)) {
// 如果未指定排序算法和稳定性,使用快速排序算法
sortkind = NPY_QUICKSORT;
}
else if (stable == 1) {
sortkind = NPY_STABLESORT;
}
val = PyArray_Sort(self, axis, sortkind);
if (order != NULL) {
Py_XDECREF(PyArray_DESCR(self));
((PyArrayObject_fields *)self)->descr = saved;
}
if (val < 0) {
return NULL;
}
Py_RETURN_NONE;
static PyObject *
array_partition(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
// 默认轴参数为-1,排序方式为NPY_INTROSELECT
int axis=-1;
int val;
NPY_SELECTKIND sortkind = NPY_INTROSELECT;
PyObject *order = NULL;
PyArray_Descr *saved = NULL;
PyArray_Descr *newd;
PyArrayObject * ktharray;
PyObject * kthobj;
NPY_PREPARE_ARGPARSER;
// 解析参数,支持kth、axis、kind、order参数,其中kth为必选参数
if (npy_parse_arguments("partition", args, len_args, kwnames,
"kth", NULL, &kthobj,
"|axis", &PyArray_PythonPyIntFromInt, &axis,
"|kind", &PyArray_SelectkindConverter, &sortkind,
"|order", NULL, &order,
NULL, NULL, NULL) < 0) {
return NULL;
}
// 如果order为Py_None,则将其置为NULL
if (order == Py_None) {
order = NULL;
}
// 如果order不为NULL,处理字段排序
if (order != NULL) {
PyObject *new_name;
PyObject *_numpy_internal;
// 保存当前描述器
saved = PyArray_DESCR(self);
// 如果当前描述器没有字段,则抛出错误
if (!PyDataType_HASFIELDS(saved)) {
PyErr_SetString(PyExc_ValueError, "Cannot specify " \
"order when the array has no fields.");
return NULL;
}
// 导入numpy._core._internal模块
_numpy_internal = PyImport_ImportModule("numpy._core._internal");
if (_numpy_internal == NULL) {
return NULL;
}
// 调用_numpy_internal的_newnames方法生成新的字段排序
new_name = PyObject_CallMethod(_numpy_internal, "_newnames",
"OO", saved, order);
Py_DECREF(_numpy_internal);
if (new_name == NULL) {
return NULL;
}
// 创建新的描述器
newd = PyArray_DescrNew(saved);
if (newd == NULL) {
Py_DECREF(new_name);
return NULL;
}
// 替换描述器的字段排序
Py_DECREF(((_PyArray_LegacyDescr *)newd)->names);
((_PyArray_LegacyDescr *)newd)->names = new_name;
((PyArrayObject_fields *)self)->descr = newd;
}
// 将kthobj转换为PyArrayObject类型
ktharray = (PyArrayObject *)PyArray_FromAny(kthobj, NULL, 0, 1,
NPY_ARRAY_DEFAULT, NULL);
if (ktharray == NULL)
return NULL;
// 调用PyArray_Partition函数进行数组分区操作
val = PyArray_Partition(self, ktharray, axis, sortkind);
Py_DECREF(ktharray);
// 如果处理了字段排序,则恢复原始描述器
if (order != NULL) {
Py_XDECREF(PyArray_DESCR(self));
((PyArrayObject_fields *)self)->descr = saved;
}
// 如果分区操作失败,返回NULL
if (val < 0) {
return NULL;
}
// 返回None
Py_RETURN_NONE;
}
static PyObject *
array_argsort(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
// 默认轴参数为-1,排序方式为_NPY_SORT_UNDEFINED
int axis = -1;
NPY_SORTKIND sortkind = _NPY_SORT_UNDEFINED;
PyObject *order = NULL, *res;
PyArray_Descr *newd, *saved=NULL;
int stable = -1;
NPY_PREPARE_ARGPARSER;
// 解析参数,支持axis、kind、order、stable参数
if (npy_parse_arguments("argsort", args, len_args, kwnames,
"|axis", &PyArray_AxisConverter, &axis,
"|kind", &PyArray_SortkindConverter, &sortkind,
"|order", NULL, &order,
"$stable", &PyArray_OptionalBoolConverter, &stable,
NULL, NULL, NULL) < 0) {
return NULL;
}
// 如果order为Py_None,则将其置为NULL
if (order == Py_None) {
order = NULL;
}
if (order != NULL) {
PyObject *new_name;
PyObject *_numpy_internal;
saved = PyArray_DESCR(self);
// 如果数组没有字段,则无法指定顺序,返回错误
if (!PyDataType_HASFIELDS(saved)) {
PyErr_SetString(PyExc_ValueError, "Cannot specify "
"order when the array has no fields.");
return NULL;
}
// 导入 numpy 内部模块 _numpy_internal
_numpy_internal = PyImport_ImportModule("numpy._core._internal");
// 导入失败则返回空指针
if (_numpy_internal == NULL) {
return NULL;
}
// 调用 _numpy_internal 模块的 _newnames 方法获取新的字段名
new_name = PyObject_CallMethod(_numpy_internal, "_newnames",
"OO", saved, order);
Py_DECREF(_numpy_internal);
// 如果调用失败则返回空指针
if (new_name == NULL) {
return NULL;
}
// 复制原始描述符 saved 并将其赋值给 newd
newd = PyArray_DescrNew(saved);
// 如果复制失败则释放 new_name 并返回空指针
if (newd == NULL) {
Py_DECREF(new_name);
return NULL;
}
// 释放原始描述符 newd 的 names 成员
Py_DECREF(((_PyArray_LegacyDescr *)newd)->names);
// 将 new_name 设置为 newd 的 names 成员
((_PyArray_LegacyDescr *)newd)->names = new_name;
// 将新的描述符 newd 设置为数组对象的描述符
((PyArrayObject_fields *)self)->descr = newd;
}
// 检查排序类型 sortkind 和稳定性 stable 参数的组合
if (sortkind != _NPY_SORT_UNDEFINED && stable != -1) {
// 如果同时提供了 `kind` 和 `stable` 参数,则返回错误
PyErr_SetString(PyExc_ValueError,
"`kind` and `stable` parameters can't be provided at "
"the same time. Use only one of them.");
return NULL;
}
else if ((sortkind == _NPY_SORT_UNDEFINED && stable == -1) || (stable == 0)) {
// 如果未指定排序类型且稳定性为 -1 或者稳定性为 0,则使用快速排序
sortkind = NPY_QUICKSORT;
}
else if (stable == 1) {
// 如果稳定性为 1,则使用稳定排序
sortkind = NPY_STABLESORT;
}
// 调用 PyArray_ArgSort 对数组进行排序并返回结果
res = PyArray_ArgSort(self, axis, sortkind);
// 如果传入了排序顺序的参数,则恢复原始描述符
if (order != NULL) {
// 释放当前数组对象的描述符
Py_XDECREF(PyArray_DESCR(self));
// 将原始描述符 saved 重新赋值给数组对象的描述符
((PyArrayObject_fields *)self)->descr = saved;
}
// 返回排序后的数组对象
return PyArray_Return((PyArrayObject *)res);
static PyObject *
array_argpartition(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
int axis = -1;
NPY_SELECTKIND sortkind = NPY_INTROSELECT;
PyObject *order = NULL, *res;
PyArray_Descr *newd, *saved=NULL;
PyObject * kthobj;
PyArrayObject * ktharray;
NPY_PREPARE_ARGPARSER;
if (npy_parse_arguments("argpartition", args, len_args, kwnames,
"kth", NULL, &kthobj,
"|axis", &PyArray_AxisConverter, &axis,
"|kind", &PyArray_SelectkindConverter, &sortkind,
"|order", NULL, &order,
NULL, NULL, NULL) < 0) {
return NULL;
}
if (order == Py_None) {
order = NULL;
}
if (order != NULL) {
PyObject *new_name;
PyObject *_numpy_internal;
saved = PyArray_DESCR(self);
if (!PyDataType_HASFIELDS(saved)) {
PyErr_SetString(PyExc_ValueError, "Cannot specify "
"order when the array has no fields.");
return NULL;
}
_numpy_internal = PyImport_ImportModule("numpy._core._internal");
if (_numpy_internal == NULL) {
return NULL;
}
new_name = PyObject_CallMethod(_numpy_internal, "_newnames",
"OO", saved, order);
Py_DECREF(_numpy_internal);
if (new_name == NULL) {
return NULL;
}
newd = PyArray_DescrNew(saved);
if (newd == NULL) {
Py_DECREF(new_name);
return NULL;
}
Py_DECREF(((_PyArray_LegacyDescr *)newd)->names);
((_PyArray_LegacyDescr *)newd)->names = new_name;
((PyArrayObject_fields *)self)->descr = newd;
}
ktharray = (PyArrayObject *)PyArray_FromAny(kthobj, NULL, 0, 1,
NPY_ARRAY_DEFAULT, NULL);
if (ktharray == NULL)
return NULL;
res = PyArray_ArgPartition(self, ktharray, axis, sortkind);
Py_DECREF(ktharray);
if (order != NULL) {
Py_XDECREF(PyArray_DESCR(self));
((PyArrayObject_fields *)self)->descr = saved;
}
return PyArray_Return((PyArrayObject *)res);
}
static PyObject *
array_searchsorted(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
PyObject *keys;
PyObject *sorter;
NPY_SEARCHSIDE side = NPY_SEARCHLEFT;
NPY_PREPARE_ARGPARSER;
sorter = NULL;
if (npy_parse_arguments("searchsorted", args, len_args, kwnames,
"v", NULL, &keys,
"|side", &PyArray_SearchsideConverter, &side,
"|sorter", NULL, &sorter,
NULL, NULL, NULL) < 0) {
return NULL;
}
if (sorter == Py_None) {
sorter = NULL;
}
return PyArray_Return((PyArrayObject *)PyArray_SearchSorted(self, keys, side, sorter));
}
_deepcopy_call(char *iptr, char *optr, PyArray_Descr *dtype,
PyObject *deepcopy, PyObject *visit)
{
// 检查 dtype 是否具有引用计数,若没有则返回 0
if (!PyDataType_REFCHK(dtype)) {
return 0;
}
// 如果 dtype 具有字段
else if (PyDataType_HASFIELDS(dtype)) {
PyObject *key, *value, *title = NULL;
PyArray_Descr *new;
int offset, res;
Py_ssize_t pos = 0;
// 遍历 dtype 的字段
while (PyDict_Next(PyDataType_FIELDS(dtype), &pos, &key, &value)) {
// 跳过标题字段
if (NPY_TITLE_KEY(key, value)) {
continue;
}
// 解析字段值,获取新的 dtype 和偏移量
if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset,
&title)) {
return -1;
}
// 递归调用 _deepcopy_call 处理字段数据
res = _deepcopy_call(iptr + offset, optr + offset, new,
deepcopy, visit);
if (res < 0) {
return -1;
}
}
}
// 如果 dtype 没有字段
else {
PyObject *itemp, *otemp;
PyObject *res;
// 从 iptr 和 optr 处复制对象引用
memcpy(&itemp, iptr, sizeof(itemp));
memcpy(&otemp, optr, sizeof(otemp));
// 如果 itemp 为空,则使用 Py_None
if (itemp == NULL) {
itemp = Py_None;
}
// 增加对象的引用计数
Py_INCREF(itemp);
// 调用 deepcopy 处理该参数
/* 调用 deepcopy 处理该参数 */
res = PyObject_CallFunctionObjArgs(deepcopy, itemp, visit, NULL);
Py_DECREF(itemp);
if (res == NULL) {
return -1;
}
// 减少原对象的引用计数,并将结果复制到 optr 处
Py_XDECREF(otemp);
memcpy(optr, &res, sizeof(res));
}
// 返回成功
return 0;
}
static PyObject *
array_deepcopy(PyArrayObject *self, PyObject *args)
{
PyArrayObject *copied_array;
PyObject *visit;
NpyIter *iter = NULL;
NpyIter_IterNextFunc *iternext;
char *data;
char **dataptr;
npy_intp *strideptr, *innersizeptr;
npy_intp stride, count;
PyObject *copy, *deepcopy;
int deepcopy_res;
// 解析输入参数,获取 visit 对象
if (!PyArg_ParseTuple(args, "O:__deepcopy__", &visit)) {
return NULL;
}
// 复制 self 对象,保持原有顺序
copied_array = (PyArrayObject*) PyArray_NewCopy(self, NPY_KEEPORDER);
if (copied_array == NULL) {
return NULL;
}
// 如果 self 不包含引用计数,则直接返回复制后的数组
if (!PyDataType_REFCHK(PyArray_DESCR(self))) {
return (PyObject *)copied_array;
}
// 如果数组包含对象,需要进行深度复制
copy = PyImport_ImportModule("copy");
if (copy == NULL) {
Py_DECREF(copied_array);
return NULL;
}
// 获取 copy 模块的 deepcopy 函数
deepcopy = PyObject_GetAttrString(copy, "deepcopy");
Py_DECREF(copy);
if (deepcopy == NULL) {
goto error;
}
// 创建 NpyIter 对象以便迭代数组
iter = NpyIter_New(copied_array,
NPY_ITER_READWRITE |
NPY_ITER_EXTERNAL_LOOP |
NPY_ITER_REFS_OK |
NPY_ITER_ZEROSIZE_OK,
NPY_KEEPORDER, NPY_NO_CASTING,
NULL);
if (iter == NULL) {
goto error;
}
if (NpyIter_GetIterSize(iter) != 0) {
iternext = NpyIter_GetIterNext(iter, NULL);
if (iternext == NULL) {
goto error;
}
dataptr = NpyIter_GetDataPtrArray(iter);
strideptr = NpyIter_GetInnerStrideArray(iter);
innersizeptr = NpyIter_GetInnerLoopSizePtr(iter);
do {
data = *dataptr;
stride = *strideptr;
count = *innersizeptr;
while (count--) {
deepcopy_res = _deepcopy_call(data, data, PyArray_DESCR(copied_array),
deepcopy, visit);
if (deepcopy_res == -1) {
goto error;
}
data += stride;
}
} while (iternext(iter));
}
Py_DECREF(deepcopy);
if (!NpyIter_Deallocate(iter)) {
Py_DECREF(copied_array);
return NULL;
}
return (PyObject *)copied_array;
error:
Py_DECREF(deepcopy);
Py_DECREF(copied_array);
NpyIter_Deallocate(iter);
return NULL;
/* Convert Array to flat list (using getitem) */
static PyObject *
_getlist_pkl(PyArrayObject *self)
{
PyObject *theobject;
PyArrayIterObject *iter = NULL;
PyObject *list;
PyArray_GetItemFunc *getitem;
// 获取数组元素的获取函数
getitem = PyDataType_GetArrFuncs(PyArray_DESCR(self))->getitem;
// 创建数组迭代器对象
iter = (PyArrayIterObject *)PyArray_IterNew((PyObject *)self);
if (iter == NULL) {
return NULL;
}
// 创建一个空列表对象
list = PyList_New(iter->size);
if (list == NULL) {
Py_DECREF(iter);
return NULL;
}
// 遍历数组并将每个元素添加到列表中
while (iter->index < iter->size) {
theobject = getitem(iter->dataptr, self);
PyList_SET_ITEM(list, iter->index, theobject);
PyArray_ITER_NEXT(iter);
}
Py_DECREF(iter);
return list;
}
static int
_setlist_pkl(PyArrayObject *self, PyObject *list)
{
PyObject *theobject;
PyArrayIterObject *iter = NULL;
PyArray_SetItemFunc *setitem;
// 获取数组元素的设置函数
setitem = PyDataType_GetArrFuncs(PyArray_DESCR(self))->setitem;
// 创建数组迭代器对象
iter = (PyArrayIterObject *)PyArray_IterNew((PyObject *)self);
if (iter == NULL) {
return -1;
}
// 遍历数组并从列表中设置每个元素
while(iter->index < iter->size) {
theobject = PyList_GET_ITEM(list, iter->index);
setitem(theobject, iter->dataptr, self);
PyArray_ITER_NEXT(iter);
}
Py_XDECREF(iter);
return 0;
}
static PyObject *
array_reduce(PyArrayObject *self, PyObject *NPY_UNUSED(args))
{
/* version number of this pickle type. Increment if we need to
change the format. Be sure to handle the old versions in
array_setstate. */
// 定义当前 pickle 格式的版本号
const int version = 1;
PyObject *ret = NULL, *state = NULL, *obj = NULL, *mod = NULL;
PyObject *mybool, *thestr = NULL;
PyArray_Descr *descr;
/* Return a tuple of (callable object, arguments, object's state) */
/* We will put everything in the object's state, so that on UnPickle
it can use the string object as memory without a copy */
// 创建一个包含三个元素的元组对象
ret = PyTuple_New(3);
if (ret == NULL) {
return NULL;
}
// 导入 numpy._core._multiarray_umath 模块
mod = PyImport_ImportModule("numpy._core._multiarray_umath");
if (mod == NULL) {
Py_DECREF(ret);
return NULL;
}
// 获取 _reconstruct 函数对象并添加到元组中
obj = PyObject_GetAttrString(mod, "_reconstruct");
Py_DECREF(mod);
PyTuple_SET_ITEM(ret, 0, obj);
// 设置元组的第二个元素,包括类型对象、参数和一个字符
PyTuple_SET_ITEM(ret, 1,
Py_BuildValue("ONc",
(PyObject *)Py_TYPE(self),
Py_BuildValue("(N)",
PyLong_FromLong(0)),
/* dummy data-type */
'b'));
注释:
/* 现在填充对象的状态。这是一个包含5个参数的元组
1) 一个整数,表示pickle版本。
2) 一个元组,给出数组的形状。
3) 一个PyArray_Descr对象(带有正确的字节顺序设置)。
4) 一个npy_bool,表示是否按Fortran顺序存储。
5) 一个Python对象,表示数据(可以是字符串、列表或任何用户定义的对象)。
注意,因为Python没有描述一种直接将原始数据写入pickle的机制,这里首先执行了向字符串的复制。
这个问题在协议5中已得到解决,其中序列化的是缓冲区而不是字符串。
*/
state = PyTuple_New(5);
if (state == NULL) {
Py_DECREF(ret);
return NULL;
}
PyTuple_SET_ITEM(state, 0, PyLong_FromLong(version)); // 设置pickle版本号
PyTuple_SET_ITEM(state, 1, PyObject_GetAttrString((PyObject *)self,
"shape")); // 获取对象的形状属性
descr = PyArray_DESCR(self); // 获取数组的描述符
Py_INCREF(descr);
PyTuple_SET_ITEM(state, 2, (PyObject *)descr); // 设置描述符到元组
mybool = (PyArray_ISFORTRAN(self) ? Py_True : Py_False); // 检查数组是否按Fortran顺序存储
Py_INCREF(mybool);
PyTuple_SET_ITEM(state, 3, mybool); // 设置布尔值(是否按Fortran顺序)到元组
if (PyDataType_FLAGCHK(PyArray_DESCR(self), NPY_LIST_PICKLE)) { // 检查数组是否具有NPY_LIST_PICKLE标志
thestr = _getlist_pkl(self); // 如果是列表类型,获取其pickle表示
}
else {
thestr = PyArray_ToString(self, NPY_ANYORDER); // 否则,将数组转换为字符串表示
}
if (thestr == NULL) {
Py_DECREF(ret);
Py_DECREF(state);
return NULL;
}
PyTuple_SET_ITEM(state, 4, thestr); // 设置数据对象的字符串表示到元组
PyTuple_SET_ITEM(ret, 2, state); // 将状态元组设置为返回元组的第三个元素
return ret; // 返回填充好的返回元组
/* Closing brace for the array_reduce_ex_picklebuffer function */
/* Declare variables to hold references to Python objects */
PyObject *numeric_mod = NULL, *from_buffer_func = NULL;
PyObject *pickle_module = NULL, *picklebuf_class = NULL;
PyObject *picklebuf_args = NULL;
PyObject *buffer = NULL, *transposed_array = NULL;
PyArray_Descr *descr = NULL;
char order;
/* Obtain the descriptor of the NumPy array object */
descr = PyArray_DESCR(self);
/* Import the 'pickle' module */
pickle_module = PyImport_ImportModule("pickle");
if (pickle_module == NULL){
return NULL;
}
/* Get the 'PickleBuffer' class from the 'pickle' module */
picklebuf_class = PyObject_GetAttrString(pickle_module, "PickleBuffer");
Py_DECREF(pickle_module);
if (picklebuf_class == NULL) {
return NULL;
}
/* Construct a PickleBuffer of the array */
if (!PyArray_IS_C_CONTIGUOUS((PyArrayObject*) self) &&
PyArray_IS_F_CONTIGUOUS((PyArrayObject*) self)) {
/* Handle Fortran-contiguous arrays */
order = 'F';
/* Transpose the array to ensure C-contiguity */
transposed_array = PyArray_Transpose((PyArrayObject*)self, NULL);
/* Build arguments for PickleBuffer with transposed array */
picklebuf_args = Py_BuildValue("(N)", transposed_array);
}
else {
/* Handle C-contiguous arrays */
order = 'C';
/* Build arguments for PickleBuffer with original array */
picklebuf_args = Py_BuildValue("(O)", self);
}
if (picklebuf_args == NULL) {
Py_DECREF(picklebuf_class);
return NULL;
}
/* Create a PickleBuffer instance */
buffer = PyObject_CallObject(picklebuf_class, picklebuf_args);
Py_DECREF(picklebuf_class);
Py_DECREF(picklebuf_args);
if (buffer == NULL) {
/* Handle case where buffer creation fails by falling back to regular __reduce_ex__ */
PyErr_Clear();
return array_reduce_ex_regular(self, protocol);
}
/* Import the '_frombuffer' function from 'numpy._core.numeric' */
numeric_mod = PyImport_ImportModule("numpy._core.numeric");
if (numeric_mod == NULL) {
Py_DECREF(buffer);
return NULL;
}
/* Get the '_frombuffer' function */
from_buffer_func = PyObject_GetAttrString(numeric_mod,
"_frombuffer");
Py_DECREF(numeric_mod);
if (from_buffer_func == NULL) {
Py_DECREF(buffer);
return NULL;
}
return Py_BuildValue("N(NONN)",
from_buffer_func, buffer, (PyObject *)descr,
PyObject_GetAttrString((PyObject *)self, "shape"),
PyUnicode_FromStringAndSize(&order, 1));
static PyObject *
array_setstate(PyArrayObject *self, PyObject *args)
{
PyObject *shape; // 存储数组形状的 Python 对象
PyArray_Descr *typecode; // 存储数组数据类型的描述符
int version = 1; // 序列化版本号,默认为 1
int is_f_order; // 指示数组是否是 Fortran(列优先)顺序的标志
PyObject *rawdata = NULL; // 原始数据的 Python 对象指针
char *datastr; // 数据的字符串表示
Py_ssize_t len; // 数据字符串的长度
npy_intp dimensions[NPY_MAXDIMS]; // 存储数组各维度大小的数组
int nd; // 数组的维度数
npy_intp nbytes; // 数组总字节数
int overflowed; // 标志是否发生溢出
PyArrayObject_fields *fa = (PyArrayObject_fields *)self; // 将 self 强制转换为 PyArrayObject_fields 结构体指针
/* This will free any memory associated with a and
use the string in setstate as the (writeable) memory.
*/
// 尝试解析输入参数 args,期望格式为 "(iO!O!iO):__setstate__"
if (!PyArg_ParseTuple(args, "(iO!O!iO):__setstate__",
&version,
&PyTuple_Type, &shape,
&PyArrayDescr_Type, &typecode,
&is_f_order,
&rawdata)) {
PyErr_Clear(); // 清除异常状态
version = 0; // 如果解析失败,将版本号设为 0
// 尝试解析参数,格式为 "(O!O!iO):__setstate__"
if (!PyArg_ParseTuple(args, "(O!O!iO):__setstate__",
&PyTuple_Type, &shape,
&PyArrayDescr_Type, &typecode,
&is_f_order,
&rawdata)) {
return NULL; // 如果再次解析失败,返回 NULL
}
}
/* If we ever need another pickle format, increment the version
number. But we should still be able to handle the old versions.
We've only got one right now. */
// 检查版本号是否为已知版本(0 或 1),否则报错
if (version != 1 && version != 0) {
PyErr_Format(PyExc_ValueError,
"can't handle version %d of numpy.ndarray pickle",
version);
return NULL; // 返回错误信息
}
/*
* Reassigning fa->descr messes with the reallocation strategy,
* since fa could be a 0-d or scalar, and then
* PyDataMem_UserFREE will be confused
*/
// 获取数组占用的字节数,如果为零则设为一
size_t n_tofree = PyArray_NBYTES(self);
if (n_tofree == 0) {
n_tofree = 1;
}
Py_XDECREF(PyArray_DESCR(self)); // 释放原先的描述符
fa->descr = typecode; // 用新的描述符替换旧的描述符
Py_INCREF(typecode); // 增加描述符的引用计数
nd = PyArray_IntpFromSequence(shape, dimensions, NPY_MAXDIMS); // 从形状元组中提取数组维度信息
# 如果维度数小于 0,返回 NULL
if (nd < 0) {
return NULL;
}
# 定义一个布尔变量 `empty`,初始化为 False
npy_bool empty = NPY_FALSE;
# 初始化 `nbytes` 为 1
nbytes = 1;
# 遍历维度数组 `dimensions`,计算总字节数 `nbytes`
for (int i = 0; i < nd; i++) {
# 如果某个维度小于 0,抛出类型错误并返回 NULL
if (dimensions[i] < 0) {
PyErr_SetString(PyExc_TypeError,
"impossible dimension while unpickling array");
return NULL;
}
# 如果某个维度为 0,将 `empty` 置为 True
if (dimensions[i] == 0) {
empty = NPY_TRUE;
}
# 使用 `npy_mul_sizes_with_overflow` 计算 `nbytes` 和当前维度的乘积,检查是否溢出
overflowed = npy_mul_sizes_with_overflow(
&nbytes, nbytes, dimensions[i]);
# 如果溢出,返回内存错误
if (overflowed) {
return PyErr_NoMemory();
}
}
# 计算 `nbytes` 和数组每个元素的大小的乘积,检查是否溢出
overflowed = npy_mul_sizes_with_overflow(
&nbytes, nbytes, PyArray_ITEMSIZE(self));
# 如果溢出,返回内存错误
if (overflowed) {
return PyErr_NoMemory();
}
# 如果数组为空(`empty` 为 True),将 `nbytes` 设为 0
if (empty) {
nbytes = 0;
}
# 如果 `typecode` 标志包含 `NPY_LIST_PICKLE`
if (PyDataType_FLAGCHK(typecode, NPY_LIST_PICKLE)) {
# 检查 `rawdata` 是否为列表,若不是,抛出类型错误并返回 NULL
if (!PyList_Check(rawdata)) {
PyErr_SetString(PyExc_TypeError,
"object pickle not returning list");
return NULL;
}
}
else {
# 增加 `rawdata` 的引用计数,以防止被释放
Py_INCREF(rawdata);
/* 与 Python 2 NumPy pickles 的向后兼容性 */
# 如果 `rawdata` 是 Unicode 对象,转换为 Latin1 字符串
if (PyUnicode_Check(rawdata)) {
PyObject *tmp;
tmp = PyUnicode_AsLatin1String(rawdata);
Py_DECREF(rawdata);
rawdata = tmp;
# 如果转换失败,抛出更详细的值错误信息并返回 NULL
if (tmp == NULL) {
PyErr_SetString(PyExc_ValueError,
("Failed to encode latin1 string when unpickling a Numpy array. "
"pickle.load(a, encoding='latin1') is assumed."));
return NULL;
}
}
# 检查 `rawdata` 是否为字节串,若不是,抛出类型错误并返回 NULL
if (!PyBytes_Check(rawdata)) {
PyErr_SetString(PyExc_TypeError,
"pickle not returning string");
Py_DECREF(rawdata);
return NULL;
}
# 获取字节串的指针和长度
if (PyBytes_AsStringAndSize(rawdata, &datastr, &len) < 0) {
Py_DECREF(rawdata);
return NULL;
}
# 如果长度 `len` 不等于 `nbytes`,抛出值错误并返回 NULL
if (len != nbytes) {
PyErr_SetString(PyExc_ValueError,
"buffer size does not match array size");
Py_DECREF(rawdata);
return NULL;
}
}
if ((PyArray_FLAGS(self) & NPY_ARRAY_OWNDATA)) {
/*
* 如果数组标志包含 NPY_ARRAY_OWNDATA 标志位
* 分配永远不会为0,请参见 ctors.c 中的注释,第820行
*/
PyObject *handler = PyArray_HANDLER(self);
// 获取数组的内存处理器
if (handler == NULL) {
/* 如果没有找到内存处理器,则可能发生这种情况 */
PyErr_SetString(PyExc_RuntimeError,
"no memory handler found but OWNDATA flag set");
return NULL;
}
// 释放数组数据内存,并使用内存处理器进行处理
PyDataMem_UserFREE(PyArray_DATA(self), n_tofree, handler);
// 清除数组的 NPY_ARRAY_OWNDATA 标志位
PyArray_CLEARFLAGS(self, NPY_ARRAY_OWNDATA);
}
// 释放数组的基础对象引用
Py_XDECREF(PyArray_BASE(self));
// 将 fa 结构体中的 base 指针设置为 NULL
fa->base = NULL;
// 清除数组的 NPY_ARRAY_WRITEBACKIFCOPY 标志位
PyArray_CLEARFLAGS(self, NPY_ARRAY_WRITEBACKIFCOPY);
// 如果数组的维度不为 NULL
if (PyArray_DIMS(self) != NULL) {
// 释放缓存中的维度数组
npy_free_cache_dim_array(self);
// 将 fa 结构体中的 dimensions 指针设置为 NULL
fa->dimensions = NULL;
}
// 将 fa 结构体中的 flags 设置为 NPY_ARRAY_DEFAULT
fa->flags = NPY_ARRAY_DEFAULT;
// 将 fa 结构体中的 nd 设置为当前数组的维度数
fa->nd = nd;
// 如果数组的维度数大于0
if (nd > 0) {
// 分配并缓存数组的维度数组,大小为 2 * nd
fa->dimensions = npy_alloc_cache_dim(2 * nd);
// 如果分配失败,则返回内存错误异常
if (fa->dimensions == NULL) {
return PyErr_NoMemory();
}
// 设置 fa 结构体中的 strides 指针为数组的维度数组的第 nd 个元素
fa->strides = PyArray_DIMS(self) + nd;
// 如果 nd 大于0,则将 dimensions 数组的前 nd 个元素复制到数组的维度数组中
if (nd) {
memcpy(PyArray_DIMS(self), dimensions, sizeof(npy_intp)*nd);
}
// 根据数组的内存布局(是否按行或按列连续),填充数组的步长数组
_array_fill_strides(PyArray_STRIDES(self), dimensions, nd,
PyArray_ITEMSIZE(self),
(is_f_order ? NPY_ARRAY_F_CONTIGUOUS :
NPY_ARRAY_C_CONTIGUOUS),
&(fa->flags));
}
// 检查 typecode 是否包含 NPY_LIST_PICKLE 标志
if (!PyDataType_FLAGCHK(typecode, NPY_LIST_PICKLE)) {
// 检查是否需要进行字节交换
int swap = PyArray_ISBYTESWAPPED(self);
/* Bytes should always be considered immutable, but we just grab the
* pointer if they are large, to save memory. */
// 如果数组不是按字节对齐的,或者需要交换字节序,或者长度较小于等于 1000,则不直接使用原始数据指针
if (!IsAligned(self) || swap || (len <= 1000)) {
// 获取数组的字节大小
npy_intp num = PyArray_NBYTES(self);
if (num == 0) {
num = 1;
}
/* Store the handler in case the default is modified */
// 存储当前的内存处理器,以防默认值被修改
Py_XDECREF(fa->mem_handler);
fa->mem_handler = PyDataMem_GetHandler();
if (fa->mem_handler == NULL) {
// 如果获取内存处理器失败,清理资源并返回空值
Py_CLEAR(fa->mem_handler);
Py_DECREF(rawdata);
return NULL;
}
// 使用用户分配内存函数创建新的数据空间
fa->data = PyDataMem_UserNEW(num, PyArray_HANDLER(self));
if (PyArray_DATA(self) == NULL) {
// 如果分配内存失败,清理资源并返回内存错误
Py_CLEAR(fa->mem_handler);
Py_DECREF(rawdata);
return PyErr_NoMemory();
}
if (swap) {
/* byte-swap on pickle-read */
// 在 pickle 读取时进行字节交换
npy_intp numels = PyArray_SIZE(self);
PyDataType_GetArrFuncs(PyArray_DESCR(self))->copyswapn(PyArray_DATA(self),
PyArray_ITEMSIZE(self),
datastr, PyArray_ITEMSIZE(self),
numels, 1, self);
// 如果数组不是扩展类型且没有元数据,则创建一个描述符
if (!(PyArray_ISEXTENDED(self) ||
PyArray_DESCR(self)->metadata ||
PyDataType_C_METADATA(PyArray_DESCR(self)))) {
fa->descr = PyArray_DescrFromType(
PyArray_DESCR(self)->type_num);
}
else {
// 否则根据 typecode 创建一个新的描述符
fa->descr = PyArray_DescrNew(typecode);
if (fa->descr == NULL) {
// 如果创建描述符失败,清理资源并返回空值
Py_CLEAR(fa->mem_handler);
Py_DECREF(rawdata);
return NULL;
}
// 调整字节顺序
if (PyArray_DESCR(self)->byteorder == NPY_BIG) {
PyArray_DESCR(self)->byteorder = NPY_LITTLE;
}
else if (PyArray_DESCR(self)->byteorder == NPY_LITTLE) {
PyArray_DESCR(self)->byteorder = NPY_BIG;
}
}
// 释放 typecode 对象
Py_DECREF(typecode);
}
else {
// 否则直接复制数据到数组内存中
memcpy(PyArray_DATA(self), datastr, PyArray_NBYTES(self));
}
// 设置数组的 OWN_DATA 标志
PyArray_ENABLEFLAGS(self, NPY_ARRAY_OWNDATA);
fa->base = NULL;
// 释放原始数据对象引用
Py_DECREF(rawdata);
}
else {
/* The handlers should never be called in this case */
// 在这种情况下,不应调用处理器
// 清空内存处理器对象引用
Py_XDECREF(fa->mem_handler);
fa->mem_handler = NULL;
// 直接使用数据指针
fa->data = datastr;
// 设置数组的基本对象为 rawdata
if (PyArray_SetBaseObject(self, rawdata) < 0) {
// 设置失败时,释放 rawdata 引用并返回空值
Py_DECREF(rawdata);
return NULL;
}
}
}
# 如果条件不满足进入 else 分支,否则执行以下代码块
else:
# 获取数组的字节大小
npy_intp num = PyArray_NBYTES(self);
# 如果数组大小为 0,则设置为 1
if (num == 0) {
num = 1;
}
/* 存储函数以备默认处理程序修改时使用 */
// 释放先前的内存处理器并获取当前的内存处理器
Py_XDECREF(fa->mem_handler);
fa->mem_handler = PyDataMem_GetHandler();
// 如果获取内存处理器失败,则返回空指针
if (fa->mem_handler == NULL) {
return NULL;
}
// 使用用户定义的内存分配器分配内存,并将结果存储到 fa->data 中
fa->data = PyDataMem_UserNEW(num, PyArray_HANDLER(self));
// 如果数据指针为空,则清理内存处理器并返回内存错误异常
if (PyArray_DATA(self) == NULL) {
Py_CLEAR(fa->mem_handler);
return PyErr_NoMemory();
}
// 如果数组描述对象需要初始化,则使用 0 填充数据
if (PyDataType_FLAGCHK(PyArray_DESCR(self), NPY_NEEDS_INIT)) {
memset(PyArray_DATA(self), 0, PyArray_NBYTES(self));
}
// 设置数组拥有数据的标志
PyArray_ENABLEFLAGS(self, NPY_ARRAY_OWNDATA);
// 将 fa->base 设置为 NULL
fa->base = NULL;
// 将原始数据设置到列表中,如果失败则返回空指针
if (_setlist_pkl(self, rawdata) < 0) {
return NULL;
}
}
// 更新数组的标志
PyArray_UpdateFlags(self, NPY_ARRAY_UPDATE_ALL);
// 返回 None 对象
Py_RETURN_NONE;
/*NUMPY_API*/
// 定义 PyArray_Dump 函数,用于将数组对象序列化到文件中
NPY_NO_EXPORT int
PyArray_Dump(PyObject *self, PyObject *file, int protocol)
{
PyObject *ret;
// 缓存导入 numpy._core._methods 模块中的 _dump 函数
npy_cache_import("numpy._core._methods", "_dump",
&npy_thread_unsafe_state._dump);
// 如果 _dump 函数未找到,则返回错误
if (npy_thread_unsafe_state._dump == NULL) {
return -1;
}
// 根据 protocol 的值选择合适的参数调用 _dump 函数,并获得返回对象
if (protocol < 0) {
ret = PyObject_CallFunction(
npy_thread_unsafe_state._dump, "OO", self, file);
}
else {
ret = PyObject_CallFunction(
npy_thread_unsafe_state._dump, "OOi", self, file, protocol);
}
// 如果调用失败,则返回错误
if (ret == NULL) {
return -1;
}
// 释放返回对象的引用计数
Py_DECREF(ret);
// 返回成功状态
return 0;
}
/*NUMPY_API*/
// 定义 PyArray_Dumps 函数,用于将数组对象序列化为 Python 字符串
NPY_NO_EXPORT PyObject *
PyArray_Dumps(PyObject *self, int protocol)
{
// 缓存导入 numpy._core._methods 模块中的 _dumps 函数
npy_cache_import("numpy._core._methods", "_dumps",
&npy_thread_unsafe_state._dumps);
// 如果 _dumps 函数未找到,则返回空对象
if (npy_thread_unsafe_state._dumps == NULL) {
return NULL;
}
// 根据 protocol 的值选择合适的参数调用 _dumps 函数,并返回其结果对象
if (protocol < 0) {
return PyObject_CallFunction(npy_thread_unsafe_state._dumps, "O", self);
}
else {
return PyObject_CallFunction(
npy_thread_unsafe_state._dumps, "Oi", self, protocol);
}
}
static PyObject *
// 定义 array_dump 函数,将数组对象的 _dump 方法转发给 numpy._core._methods 模块
array_dump(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
// 调用 NPY_FORWARD_NDARRAY_METHOD 宏,转发 _dump 方法
NPY_FORWARD_NDARRAY_METHOD(_dump);
}
static PyObject *
// 定义 array_dumps 函数,将数组对象的 _dumps 方法转发给 numpy._core._methods 模块
array_dumps(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
// 调用 NPY_FORWARD_NDARRAY_METHOD 宏,转发 _dumps 方法
NPY_FORWARD_NDARRAY_METHOD(_dumps);
}
static PyObject *
// 定义 array_sizeof 函数,计算数组对象占用的内存大小
array_sizeof(PyArrayObject *self, PyObject *NPY_UNUSED(args))
{
// 计算对象基本大小加上维度和步长所需的内存大小
Py_ssize_t nbytes = Py_TYPE(self)->tp_basicsize +
PyArray_NDIM(self) * sizeof(npy_intp) * 2;
// 如果数组拥有数据内存,则加上数据内存的大小
if (PyArray_CHKFLAGS(self, NPY_ARRAY_OWNDATA)) {
nbytes += PyArray_NBYTES(self);
}
// 返回内存大小的 Python 长整型对象
return PyLong_FromSsize_t(nbytes);
}
static PyObject *
// 定义 array_transpose 函数,对数组对象进行转置操作
array_transpose(PyArrayObject *self, PyObject *args)
{
PyObject *shape = Py_None;
Py_ssize_t n = PyTuple_Size(args);
PyArray_Dims permute;
PyObject *ret;
// 根据参数数量设置转置形状
if (n > 1) {
shape = args;
}
else if (n == 1) {
shape = PyTuple_GET_ITEM(args, 0);
}
// 根据形状是否为 None 选择转置方法
if (shape == Py_None) {
ret = PyArray_Transpose(self, NULL);
}
else {
// 将形状参数转换为数组维度对象
if (!PyArray_IntpConverter(shape, &permute)) {
return NULL;
}
// 执行带有指定维度对象的转置操作
ret = PyArray_Transpose(self, &permute);
npy_free_cache_dim_obj(permute);
}
// 返回转置结果对象
return ret;
}
#define _CHKTYPENUM(typ) ((typ) ? (typ)->type_num : NPY_NOTYPE)
static PyObject *
// 定义 array_mean 函数,将数组对象的 _mean 方法转发给 numpy._core._methods 模块
array_mean(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
// 调用 NPY_FORWARD_NDARRAY_METHOD 宏,转发 _mean 方法
NPY_FORWARD_NDARRAY_METHOD(_mean);
}
static PyObject *
// 定义 array_sum 函数,将数组对象的 _sum 方法转发给 numpy._core._methods 模块
array_sum(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
// 调用 NPY_FORWARD_NDARRAY_METHOD 宏,转发 _sum 方法
NPY_FORWARD_NDARRAY_METHOD(_sum);
}
static PyObject *
// 定义 array_cumsum 函数,计算数组对象的累积和
array_cumsum(PyArrayObject *self, PyObject *args, PyObject *kwds)
{
int axis = NPY_RAVEL_AXIS;
// ...
}
# 定义一个指向数组描述符的指针,并初始化为 NULL
PyArray_Descr *dtype = NULL;
# 定义一个指向数组对象的指针,并初始化为 NULL
PyArrayObject *out = NULL;
# 定义一个整型变量 rtype,用于存储类型检查后的结果
int rtype;
# 静态字符数组,用于解析参数时指定关键字的名称
static char *kwlist[] = {"axis", "dtype", "out", NULL};
# 使用 PyArg_ParseTupleAndKeywords 函数解析传入的参数和关键字参数
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&O&O&:cumsum", kwlist,
PyArray_AxisConverter, &axis,
PyArray_DescrConverter2, &dtype,
PyArray_OutputConverter, &out)) {
# 如果解析失败,则释放 dtype 并返回 NULL
Py_XDECREF(dtype);
return NULL;
}
# 调用 _CHKTYPENUM 函数,检查 dtype 的类型,并将结果存储在 rtype 中
rtype = _CHKTYPENUM(dtype);
# 释放 dtype,因为不再需要它
Py_XDECREF(dtype);
# 调用 PyArray_CumSum 函数执行累积和操作,并返回其结果
return PyArray_CumSum(self, axis, rtype, out);
static PyObject *
array_prod(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
// 使用宏定义调用 _prod 方法,执行数组的乘积计算
NPY_FORWARD_NDARRAY_METHOD(_prod);
}
static PyObject *
array_cumprod(PyArrayObject *self, PyObject *args, PyObject *kwds)
{
int axis = NPY_RAVEL_AXIS; // 设置默认轴为展平(ravel)轴
PyArray_Descr *dtype = NULL; // 初始化 dtype 为空指针
PyArrayObject *out = NULL; // 初始化输出数组对象为空
int rtype;
static char *kwlist[] = {"axis", "dtype", "out", NULL}; // 定义关键字列表
// 解析输入参数,支持 axis、dtype、out 作为关键字参数
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&O&O&:cumprod", kwlist,
PyArray_AxisConverter, &axis,
PyArray_DescrConverter2, &dtype,
PyArray_OutputConverter, &out)) {
Py_XDECREF(dtype); // 解析失败时释放 dtype
return NULL; // 返回空指针
}
rtype = _CHKTYPENUM(dtype); // 获取 dtype 的类型编号
Py_XDECREF(dtype); // 释放 dtype
return PyArray_CumProd(self, axis, rtype, out); // 调用 NumPy 的累积乘积函数
}
static PyObject *
array_dot(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
PyObject *a = (PyObject *)self, *b, *o = NULL; // 初始化变量 a(self)、b 和 o(输出对象)
PyArrayObject *ret; // 定义返回的数组对象 ret
NPY_PREPARE_ARGPARSER; // 准备参数解析
// 解析参数列表,支持输入数组 b 和输出数组对象 o
if (npy_parse_arguments("dot", args, len_args, kwnames,
"b", NULL, &b,
"|out", NULL, &o,
NULL, NULL, NULL) < 0) {
return NULL; // 解析失败时返回空指针
}
if (o != NULL) { // 如果输出对象 o 不为空
if (o == Py_None) { // 如果 o 是 None
o = NULL; // 将 o 设置为 NULL
}
else if (!PyArray_Check(o)) { // 如果 o 不是数组对象
PyErr_SetString(PyExc_TypeError,
"'out' must be an array"); // 抛出类型错误异常
return NULL; // 返回空指针
}
}
// 调用 NumPy 的矩阵乘积函数,返回结果数组对象
ret = (PyArrayObject *)PyArray_MatrixProduct2(a, b, (PyArrayObject *)o);
return PyArray_Return(ret); // 返回结果数组对象
}
static PyObject *
array_any(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
// 使用宏定义调用 _any 方法,执行数组的逻辑或操作
NPY_FORWARD_NDARRAY_METHOD(_any);
}
static PyObject *
array_all(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
// 使用宏定义调用 _all 方法,执行数组的逻辑与操作
NPY_FORWARD_NDARRAY_METHOD(_all);
}
static PyObject *
array_stddev(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
// 使用宏定义调用 _std 方法,计算数组的标准差
NPY_FORWARD_NDARRAY_METHOD(_std);
}
static PyObject *
array_variance(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
// 使用宏定义调用 _var 方法,计算数组的方差
NPY_FORWARD_NDARRAY_METHOD(_var);
}
static PyObject *
array_compress(PyArrayObject *self, PyObject *args, PyObject *kwds)
{
int axis = NPY_RAVEL_AXIS; // 设置默认轴为展平(ravel)轴
PyObject *condition; // 定义条件对象
PyArrayObject *out = NULL; // 初始化输出数组对象为空
static char *kwlist[] = {"condition", "axis", "out", NULL}; // 定义关键字列表
// 解析输入参数,支持 condition、axis 和 out 作为关键字参数
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&O&:compress", kwlist,
&condition,
PyArray_AxisConverter, &axis,
PyArray_OutputConverter, &out)) {
return NULL; // 解析失败时返回空指针
}
// 调用 NumPy 的压缩函数,返回结果对象
PyObject *ret = PyArray_Compress(self, condition, axis, out);
/* this matches the unpacking behavior of ufuncs */
// 这与 ufunc 的解包行为相匹配
// 返回结果对象
return ret;
}
# 如果`
# 检查指针变量 out 是否为 NULL
if (out == NULL) {
# 如果 out 为 NULL,则将 ret 强制转换为 PyArrayObject 类型并返回
return PyArray_Return((PyArrayObject *)ret);
}
else {
# 如果 out 不为 NULL,则直接返回 ret
return ret;
}
static PyObject *
array_nonzero(PyArrayObject *self, PyObject *args)
{
// 解析函数参数,确保没有参数传入
if (!PyArg_ParseTuple(args, "")) {
return NULL;
}
// 调用NumPy库函数,返回非零元素的索引
return PyArray_Nonzero(self);
}
static PyObject *
array_trace(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
// 设置默认参数和变量
int axis1 = 0, axis2 = 1, offset = 0;
PyArray_Descr *dtype = NULL;
PyArrayObject *out = NULL;
int rtype;
NPY_PREPARE_ARGPARSER;
// 解析函数的关键字参数
if (npy_parse_arguments("trace", args, len_args, kwnames,
"|offset", &PyArray_PythonPyIntFromInt, &offset,
"|axis1", &PyArray_PythonPyIntFromInt, &axis1,
"|axis2", &PyArray_PythonPyIntFromInt, &axis2,
"|dtype", &PyArray_DescrConverter2, &dtype,
"|out", &PyArray_OutputConverter, &out,
NULL, NULL, NULL) < 0) {
Py_XDECREF(dtype);
return NULL;
}
// 获取数据类型对应的类型号码
rtype = _CHKTYPENUM(dtype);
Py_XDECREF(dtype);
// 调用NumPy库函数计算数组的迹
PyObject *ret = PyArray_Trace(self, offset, axis1, axis2, rtype, out);
/* this matches the unpacking behavior of ufuncs */
// 根据输出参数的有无返回结果
if (out == NULL) {
return PyArray_Return((PyArrayObject *)ret);
}
else {
return ret;
}
}
#undef _CHKTYPENUM
static PyObject *
array_clip(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
// 调用NumPy库中的_ndarray_api方法,实现数组的剪裁操作
NPY_FORWARD_NDARRAY_METHOD(_clip);
}
static PyObject *
array_conjugate(PyArrayObject *self, PyObject *args)
{
// 定义输出参数
PyArrayObject *out = NULL;
// 解析函数参数,允许一个可选的输出参数
if (!PyArg_ParseTuple(args, "|O&:conjugate",
PyArray_OutputConverter,
&out)) {
return NULL;
}
// 调用NumPy库函数,返回数组的共轭
return PyArray_Conjugate(self, out);
}
static PyObject *
array_diagonal(PyArrayObject *self, PyObject *args, PyObject *kwds)
{
// 设置默认参数和变量
int axis1 = 0, axis2 = 1, offset = 0;
static char *kwlist[] = {"offset", "axis1", "axis2", NULL};
PyArrayObject *ret;
// 解析函数参数和关键字参数
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iii:diagonal", kwlist,
&offset,
&axis1,
&axis2)) {
return NULL;
}
// 调用NumPy库函数,返回数组的对角线元素
ret = (PyArrayObject *)PyArray_Diagonal(self, offset, axis1, axis2);
return PyArray_Return(ret);
}
static PyObject *
array_flatten(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
// 设置默认参数和变量
NPY_ORDER order = NPY_CORDER;
NPY_PREPARE_ARGPARSER;
// 解析函数参数和关键字参数
if (npy_parse_arguments("flatten", args, len_args, kwnames,
"|order", PyArray_OrderConverter, &order,
NULL, NULL, NULL) < 0) {
return NULL;
}
// 调用NumPy库函数,返回数组按照指定顺序展开后的结果
return PyArray_Flatten(self, order);
}
static PyObject *
array_ravel(PyArrayObject *self,
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
// 设置默认参数和变量
NPY_ORDER order = NPY_CORDER;
NPY_PREPARE_ARGPARSER;
// 解析函数参数和关键字参数
// 这里省略了npy_parse_arguments函数的调用,需要在此处注释说明其作用
# 如果调用 npy_parse_arguments 函数解析参数时出错(如参数数量不符合预期),则返回空值对象
if (npy_parse_arguments("ravel", args, len_args, kwnames,
"|order", PyArray_OrderConverter, &order,
NULL, NULL, NULL) < 0) {
return NULL;
}
# 调用 PyArray_Ravel 函数,对当前对象进行拉平操作,并根据给定的顺序参数进行处理
return PyArray_Ravel(self, order);
static PyObject *
array_round(PyArrayObject *self, PyObject *args, PyObject *kwds)
{
// 默认精度为0
int decimals = 0;
// 输出数组对象,默认为NULL
PyArrayObject *out = NULL;
// 关键字参数列表
static char *kwlist[] = {"decimals", "out", NULL};
// 解析参数和关键字参数
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO&:round", kwlist,
&decimals,
// 将 out 参数转换为 PyArrayObject 类型
PyArray_OutputConverter, &out)) {
return NULL;
}
// 调用 PyArray_Round 函数进行数组元素的四舍五入操作
PyObject *ret = PyArray_Round(self, decimals, out);
/* this matches the unpacking behavior of ufuncs */
// 如果未提供输出数组 out,则返回 ret 的数组对象
if (out == NULL) {
return PyArray_Return((PyArrayObject *)ret);
}
// 否则直接返回 ret
else {
return ret;
}
}
static PyObject *
array_setflags(PyArrayObject *self, PyObject *args, PyObject *kwds)
{
// 设置关键字参数列表
static char *kwlist[] = {"write", "align", "uic", NULL};
// 写入标志,默认为 Py_None
PyObject *write_flag = Py_None;
// 对齐标志,默认为 Py_None
PyObject *align_flag = Py_None;
// 写回复制标志,默认为 Py_None
PyObject *uic = Py_None;
// 记录当前数组的标志
int flagback = PyArray_FLAGS(self);
// 将数组对象强制转换为 PyArrayObject_fields 类型
PyArrayObject_fields *fa = (PyArrayObject_fields *)self;
// 解析参数和关键字参数
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOO:setflags", kwlist,
&write_flag,
&align_flag,
&uic))
return NULL;
// 如果指定了对齐标志
if (align_flag != Py_None) {
// 判断 align_flag 是否为 False
int isnot = PyObject_Not(align_flag);
if (isnot == -1) {
return NULL;
}
// 如果 align_flag 为 False,则清除 NPY_ARRAY_ALIGNED 标志位
if (isnot) {
PyArray_CLEARFLAGS(self, NPY_ARRAY_ALIGNED);
}
// 如果 align_flag 为 True,并且数组是对齐的,则启用 NPY_ARRAY_ALIGNED 标志位
else if (IsAligned(self)) {
PyArray_ENABLEFLAGS(self, NPY_ARRAY_ALIGNED);
}
// 如果 align_flag 为 True 但数组未对齐,则抛出 ValueError 异常
else {
PyErr_SetString(PyExc_ValueError,
"cannot set aligned flag of mis-"
"aligned array to True");
return NULL;
}
}
// 如果指定了写回复制标志
if (uic != Py_None) {
// 判断 uic 是否为 True
int istrue = PyObject_IsTrue(uic);
if (istrue == -1) {
return NULL;
}
// 如果 uic 为 True,则恢复原始标志并抛出 ValueError 异常
if (istrue) {
fa->flags = flagback;
PyErr_SetString(PyExc_ValueError,
"cannot set WRITEBACKIFCOPY "
"flag to True");
return NULL;
}
// 如果 uic 为 False,则清除 NPY_ARRAY_WRITEBACKIFCOPY 标志位,并释放 fa->base
else {
PyArray_CLEARFLAGS(self, NPY_ARRAY_WRITEBACKIFCOPY);
Py_XDECREF(fa->base);
fa->base = NULL;
}
}
// 检查写标志是否不是 None 对象
if (write_flag != Py_None) {
// 将写标志转换为整数值
int istrue = PyObject_IsTrue(write_flag);
// 检查转换是否失败
if (istrue == -1) {
return NULL;
}
// 如果写标志为真
else if (istrue == 1) {
// 如果数组可写
if (_IsWriteable(self)) {
/*
* _IsWritable (和 PyArray_UpdateFlags) 允许翻转这个标志,
* 尽管创建数组的 C-API 用户可能有充分的理由使其不可写,因此不建议。
*/
// 如果数组没有基础对象,并且不拥有数据,也不可写
if ((PyArray_BASE(self) == NULL) &&
!PyArray_CHKFLAGS(self, NPY_ARRAY_OWNDATA) &&
!PyArray_CHKFLAGS(self, NPY_ARRAY_WRITEABLE)) {
/* 2017-05-03, NumPy 1.17.0 */
// 发出警告提示,表明此操作不推荐使用
if (DEPRECATE("making a non-writeable array writeable "
"is deprecated for arrays without a base "
"which do not own their data.") < 0) {
return NULL;
}
}
// 启用数组的可写标志
PyArray_ENABLEFLAGS(self, NPY_ARRAY_WRITEABLE);
// 清除数组的写入警告标志
PyArray_CLEARFLAGS(self, NPY_ARRAY_WARN_ON_WRITE);
}
// 如果数组不可写
else {
// 恢复原始标志并设置错误信息
fa->flags = flagback;
PyErr_SetString(PyExc_ValueError,
"cannot set WRITEABLE "
"flag to True of this "
"array");
return NULL;
}
}
// 如果写标志为假
else {
// 清除数组的可写标志和写入警告标志
PyArray_CLEARFLAGS(self, NPY_ARRAY_WRITEABLE);
PyArray_CLEARFLAGS(self, NPY_ARRAY_WARN_ON_WRITE);
}
}
// 返回 Python 的 None 对象
Py_RETURN_NONE;
static PyObject *
array_complex(PyArrayObject *self, PyObject *NPY_UNUSED(args))
{
PyArrayObject *arr; // 定义一个 PyArrayObject 类型的指针变量 arr
PyArray_Descr *dtype; // 定义一个 PyArray_Descr 类型的指针变量 dtype
PyObject *c; // 定义一个 PyObject 类型的指针变量 c,用于存储复数对象
if (check_is_convertible_to_scalar(self) < 0) { // 检查 self 是否可以转换为标量,如果不行则返回 NULL
return NULL;
}
dtype = PyArray_DescrFromType(NPY_CDOUBLE); // 根据类型 NPY_CDOUBLE 创建一个 PyArray_Descr 对象,赋值给 dtype
if (dtype == NULL) { // 如果创建失败则返回 NULL
return NULL;
}
if (!PyArray_CanCastArrayTo(self, dtype, NPY_SAME_KIND_CASTING) &&
!(PyArray_TYPE(self) == NPY_OBJECT)) {
PyObject *descr = (PyObject*)PyArray_DESCR(self); // 获取 self 的描述符对象
Py_DECREF(dtype); // 减少 dtype 的引用计数
PyErr_Format(PyExc_TypeError,
"Unable to convert %R to complex", descr); // 报错,指示无法将 descr 转换为复数
return NULL;
}
if (PyArray_TYPE(self) == NPY_OBJECT) {
/* let python try calling __complex__ on the object. */
PyObject *args, *res;
Py_DECREF(dtype); // 减少 dtype 的引用计数
args = Py_BuildValue("(O)", *((PyObject**)PyArray_DATA(self))); // 构建一个包含 self 数据的参数元组 args
if (args == NULL) { // 如果构建失败则返回 NULL
return NULL;
}
res = PyComplex_Type.tp_new(&PyComplex_Type, args, NULL); // 调用 PyComplex_Type 的 tp_new 方法创建一个复数对象 res
Py_DECREF(args); // 减少 args 的引用计数
return res; // 返回创建的复数对象
}
arr = (PyArrayObject *)PyArray_CastToType(self, dtype, 0); // 将 self 转换为指定 dtype 类型的数组对象,赋值给 arr
if (arr == NULL) { // 如果转换失败则返回 NULL
return NULL;
}
c = PyComplex_FromCComplex(*((Py_complex*)PyArray_DATA(arr))); // 根据 arr 中的数据创建一个复数对象 c
Py_DECREF(arr); // 减少 arr 的引用计数
return c; // 返回创建的复数对象
}
static PyObject *
array_class_getitem(PyObject *cls, PyObject *args)
{
const Py_ssize_t args_len = PyTuple_Check(args) ? PyTuple_Size(args) : 1; // 获取参数元组 args 的长度
if ((args_len > 2) || (args_len == 0)) { // 如果参数长度大于2或者为0,则返回错误信息
return PyErr_Format(PyExc_TypeError,
"Too %s arguments for %s",
args_len > 2 ? "many" : "few",
((PyTypeObject *)cls)->tp_name); // 报错,指示参数数量错误
}
return Py_GenericAlias(cls, args); // 返回类的泛型别名对象
}
static PyObject *
array_array_namespace(PyArrayObject *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"api_version", NULL}; // 定义关键字参数列表
PyObject *array_api_version = Py_None; // 初始化 array_api_version 为 Py_None
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$O:__array_namespace__", kwlist,
&array_api_version)) { // 解析函数参数,如果失败则返回 NULL
return NULL;
}
if (array_api_version != Py_None) { // 如果 array_api_version 不是 Py_None
if (!PyUnicode_Check(array_api_version)) // 如果 array_api_version 不是 Unicode 类型
{
PyErr_Format(PyExc_ValueError,
"Only None and strings are allowed as the Array API version, "
"but received: %S.", array_api_version); // 报错,指示版本类型错误
return NULL;
} else if (PyUnicode_CompareWithASCIIString(array_api_version, "2021.12") != 0 &&
PyUnicode_CompareWithASCIIString(array_api_version, "2022.12") != 0)
{
PyErr_Format(PyExc_ValueError,
"Version \"%U\" of the Array API Standard is not supported.",
array_api_version); // 报错,指示不支持的版本
return NULL;
}
}
PyObject *numpy_module = PyImport_ImportModule("numpy"); // 导入 numpy 模块
if (numpy_module == NULL){ // 如果导入失败则返回 NULL
return NULL;
}
return numpy_module; // 返回导入的 numpy 模块对象
}
/* 定义一个函数,用于将数组对象移动到指定设备上
参数:
- self: 数组对象
- args: 参数元组
- kwds: 关键字参数字典
返回值:
- 成功时返回移动后的数组对象,失败时返回 NULL
*/
array_to_device(PyArrayObject *self, PyObject *args, PyObject *kwds)
{
// 静态字符数组,用于定义关键字列表
static char *kwlist[] = {"", "stream", NULL};
// 默认设备为空字符串
char *device = "";
// 流对象,默认为 Py_None
PyObject *stream = Py_None;
// 解析参数元组和关键字参数字典,期望字符串和可选对象类型的参数
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|$O:to_device", kwlist,
&device,
&stream)) {
// 解析失败时返回 NULL
return NULL;
}
// 如果 stream 不是 Py_None,抛出 ValueError 异常
if (stream != Py_None) {
PyErr_SetString(PyExc_ValueError,
"The stream argument in to_device() "
"is not supported");
return NULL;
}
// 如果设备不是 "cpu",抛出 ValueError 异常,表明不支持的设备
if (strcmp(device, "cpu") != 0) {
PyErr_Format(PyExc_ValueError,
"Unsupported device: %s.", device);
return NULL;
}
// 增加数组对象的引用计数,返回其 PyObject 类型的指针
Py_INCREF(self);
return (PyObject *)self;
}
// 非导出的 PyMethodDef 数组,用于定义数组类型的方法
NPY_NO_EXPORT PyMethodDef array_methods[] = {
/* for subtypes */
// "__array__" 方法,用 array_getarray 处理,支持位置参数和关键字参数
{"__array__",
(PyCFunction)array_getarray,
METH_VARARGS | METH_KEYWORDS, NULL},
// "__array_finalize__" 方法,用 array_finalizearray 处理,仅支持一个参数
{"__array_finalize__",
(PyCFunction)array_finalizearray,
METH_O, NULL},
// "__array_wrap__" 方法,用 array_wraparray 处理,支持位置参数
{"__array_wrap__",
(PyCFunction)array_wraparray,
METH_VARARGS, NULL},
// "__array_ufunc__" 方法,用 array_ufunc 处理,支持位置参数和关键字参数
{"__array_ufunc__",
(PyCFunction)array_ufunc,
METH_VARARGS | METH_KEYWORDS, NULL},
// "__array_function__" 方法,用 array_function 处理,支持位置参数和关键字参数
{"__array_function__",
(PyCFunction)array_function,
METH_VARARGS | METH_KEYWORDS, NULL},
/* for the sys module */
// "__sizeof__" 方法,用 array_sizeof 处理,不接受参数
{"__sizeof__",
(PyCFunction) array_sizeof,
METH_NOARGS, NULL},
/* for the copy module */
// "__copy__" 方法,用 array_copy_keeporder 处理,支持位置参数
{"__copy__",
(PyCFunction)array_copy_keeporder,
METH_VARARGS, NULL},
// "__deepcopy__" 方法,用 array_deepcopy 处理,支持位置参数
{"__deepcopy__",
(PyCFunction)array_deepcopy,
METH_VARARGS, NULL},
/* for Pickling */
// "__reduce__" 方法,用 array_reduce 处理,支持位置参数
{"__reduce__",
(PyCFunction) array_reduce,
METH_VARARGS, NULL},
// "__reduce_ex__" 方法,用 array_reduce_ex 处理,支持位置参数
{"__reduce_ex__",
(PyCFunction) array_reduce_ex,
METH_VARARGS, NULL},
// "__setstate__" 方法,用 array_setstate 处理,支持位置参数
{"__setstate__",
(PyCFunction) array_setstate,
METH_VARARGS, NULL},
// "dumps" 方法,用 array_dumps 处理,快速调用和关键字参数
{"dumps",
(PyCFunction) array_dumps,
METH_FASTCALL | METH_KEYWORDS, NULL},
// "dump" 方法,用 array_dump 处理,快速调用和关键字参数
{"dump",
(PyCFunction) array_dump,
METH_FASTCALL | METH_KEYWORDS, NULL},
// "__complex__" 方法,用 array_complex 处理,支持位置参数
{"__complex__",
(PyCFunction) array_complex,
METH_VARARGS, NULL},
// "__format__" 方法,用 array_format 处理,支持位置参数
{"__format__",
(PyCFunction) array_format,
METH_VARARGS, NULL},
/* for typing; requires python >= 3.9 */
// "__class_getitem__" 方法,用 array_class_getitem 处理,支持类和单个参数
{"__class_getitem__",
(PyCFunction)array_class_getitem,
METH_CLASS | METH_O, NULL},
/* Original and Extended methods added 2005 */
// "all" 方法,用 array_all 处理,快速调用和关键字参数
{"all",
(PyCFunction)array_all,
METH_FASTCALL | METH_KEYWORDS, NULL},
// "any" 方法,用 array_any 处理,快速调用和关键字参数
{"any",
(PyCFunction)array_any,
METH_FASTCALL | METH_KEYWORDS, NULL},
// "argmax" 方法,用 array_argmax 处理,快速调用和关键字参数
{"argmax",
(PyCFunction)array_argmax,
METH_FASTCALL | METH_KEYWORDS, NULL},
// "argmin" 方法,用 array_argmin 处理,快速调用和关键字参数
{"argmin",
(PyCFunction)array_argmin,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"argpartition",
(PyCFunction)array_argpartition,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"argsort",
(PyCFunction)array_argsort,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"astype",
(PyCFunction)array_astype,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"byteswap",
(PyCFunction)array_byteswap,
METH_VARARGS | METH_KEYWORDS, NULL},
{"choose",
(PyCFunction)array_choose,
METH_VARARGS | METH_KEYWORDS, NULL},
{"clip",
(PyCFunction)array_clip,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"compress",
(PyCFunction)array_compress,
METH_VARARGS | METH_KEYWORDS, NULL},
{"conj",
(PyCFunction)array_conjugate,
METH_VARARGS, NULL},
{"conjugate",
(PyCFunction)array_conjugate,
METH_VARARGS, NULL},
{"copy",
(PyCFunction)array_copy,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"cumprod",
(PyCFunction)array_cumprod,
METH_VARARGS | METH_KEYWORDS, NULL},
{"cumsum",
(PyCFunction)array_cumsum,
METH_VARARGS | METH_KEYWORDS, NULL},
{"diagonal",
(PyCFunction)array_diagonal,
METH_VARARGS | METH_KEYWORDS, NULL},
{"dot",
(PyCFunction)array_dot,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"fill",
(PyCFunction)array_fill,
METH_VARARGS, NULL},
{"flatten",
(PyCFunction)array_flatten,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"getfield",
(PyCFunction)array_getfield,
METH_VARARGS | METH_KEYWORDS, NULL},
{"item",
(PyCFunction)array_toscalar,
METH_VARARGS, NULL},
{"max",
(PyCFunction)array_max,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"mean",
(PyCFunction)array_mean,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"min",
(PyCFunction)array_min,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"nonzero",
(PyCFunction)array_nonzero,
METH_VARARGS, NULL},
{"partition",
(PyCFunction)array_partition,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"prod",
(PyCFunction)array_prod,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"put",
(PyCFunction)array_put,
METH_VARARGS | METH_KEYWORDS, NULL},
{"ravel",
(PyCFunction)array_ravel,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"repeat",
(PyCFunction)array_repeat,
METH_VARARGS | METH_KEYWORDS, NULL},
{"reshape",
(PyCFunction)array_reshape,
METH_VARARGS | METH_KEYWORDS, NULL},
{"resize",
(PyCFunction)array_resize,
METH_VARARGS | METH_KEYWORDS, NULL},
{"round",
(PyCFunction)array_round,
METH_VARARGS | METH_KEYWORDS, NULL},
{"searchsorted",
(PyCFunction)array_searchsorted,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"setfield",
(PyCFunction)array_setfield,
METH_VARARGS | METH_KEYWORDS, NULL},
{"setflags",
(PyCFunction)array_setflags,
METH_VARARGS | METH_KEYWORDS, NULL},
// 定义名为 "setflags" 的方法,其实现为 array_setflags,接受变长参数和关键字参数,无文档字符串
{"sort",
(PyCFunction)array_sort,
METH_FASTCALL | METH_KEYWORDS, NULL},
// 定义名为 "sort" 的方法,其实现为 array_sort,接受快速调用参数和关键字参数,无文档字符串
{"squeeze",
(PyCFunction)array_squeeze,
METH_FASTCALL | METH_KEYWORDS, NULL},
// 定义名为 "squeeze" 的方法,其实现为 array_squeeze,接受快速调用参数和关键字参数,无文档字符串
{"std",
(PyCFunction)array_stddev,
METH_FASTCALL | METH_KEYWORDS, NULL},
// 定义名为 "std" 的方法,其实现为 array_stddev,接受快速调用参数和关键字参数,无文档字符串
{"sum",
(PyCFunction)array_sum,
METH_FASTCALL | METH_KEYWORDS, NULL},
// 定义名为 "sum" 的方法,其实现为 array_sum,接受快速调用参数和关键字参数,无文档字符串
{"swapaxes",
(PyCFunction)array_swapaxes,
METH_VARARGS, NULL},
// 定义名为 "swapaxes" 的方法,其实现为 array_swapaxes,接受变长参数,无文档字符串
{"take",
(PyCFunction)array_take,
METH_FASTCALL | METH_KEYWORDS, NULL},
// 定义名为 "take" 的方法,其实现为 array_take,接受快速调用参数和关键字参数,无文档字符串
{"tobytes",
(PyCFunction)array_tobytes,
METH_VARARGS | METH_KEYWORDS, NULL},
// 定义名为 "tobytes" 的方法,其实现为 array_tobytes,接受变长参数和关键字参数,无文档字符串
{"tofile",
(PyCFunction)array_tofile,
METH_VARARGS | METH_KEYWORDS, NULL},
// 定义名为 "tofile" 的方法,其实现为 array_tofile,接受变长参数和关键字参数,无文档字符串
{"tolist",
(PyCFunction)array_tolist,
METH_VARARGS, NULL},
// 定义名为 "tolist" 的方法,其实现为 array_tolist,接受变长参数,无文档字符串
{"tostring",
(PyCFunction)array_tostring,
METH_VARARGS | METH_KEYWORDS, NULL},
// 定义名为 "tostring" 的方法,其实现为 array_tostring,接受变长参数和关键字参数,无文档字符串
{"trace",
(PyCFunction)array_trace,
METH_FASTCALL | METH_KEYWORDS, NULL},
// 定义名为 "trace" 的方法,其实现为 array_trace,接受快速调用参数和关键字参数,无文档字符串
{"transpose",
(PyCFunction)array_transpose,
METH_VARARGS, NULL},
// 定义名为 "transpose" 的方法,其实现为 array_transpose,接受变长参数,无文档字符串
{"var",
(PyCFunction)array_variance,
METH_FASTCALL | METH_KEYWORDS, NULL},
// 定义名为 "var" 的方法,其实现为 array_variance,接受快速调用参数和关键字参数,无文档字符串
{"view",
(PyCFunction)array_view,
METH_FASTCALL | METH_KEYWORDS, NULL},
// 定义名为 "view" 的方法,其实现为 array_view,接受快速调用参数和关键字参数,无文档字符串
// 用于库之间的数据交换
{"__dlpack__",
(PyCFunction)array_dlpack,
METH_FASTCALL | METH_KEYWORDS, NULL},
// 定义名为 "__dlpack__" 的方法,其实现为 array_dlpack,接受快速调用参数和关键字参数,无文档字符串
{"__dlpack_device__",
(PyCFunction)array_dlpack_device,
METH_NOARGS, NULL},
// 定义名为 "__dlpack_device__" 的方法,其实现为 array_dlpack_device,不接受参数,无文档字符串
// 用于数组 API 兼容性
{"__array_namespace__",
(PyCFunction)array_array_namespace,
METH_VARARGS | METH_KEYWORDS, NULL},
// 定义名为 "__array_namespace__" 的方法,其实现为 array_array_namespace,接受变长参数和关键字参数,无文档字符串
{"to_device",
(PyCFunction)array_to_device,
METH_VARARGS | METH_KEYWORDS, NULL},
// 定义名为 "to_device" 的方法,其实现为 array_to_device,接受变长参数和关键字参数,无文档字符串
{NULL, NULL, 0, NULL} /* sentinel */
// 结束方法列表的标志
};
注释:
// 这是一个空的代码块闭合符号。在某些编程语言(如C、C++、Java等)中,用于结束一个代码块的语法结构。
// 在此处,`;`表示空语句,仅仅是为了保持代码结构的完整性,但实际上没有任何操作或逻辑效果。
// 注意:该代码块可能位于某个条件语句、循环或函数定义的结束位置,但是在当前提供的片段中,它并没有包含具体的代码内容。
.\numpy\numpy\_core\src\multiarray\methods.h
extern NPY_NO_EXPORT PyMethodDef array_methods[]; // 声明外部数组方法的 PyMethodDef 结构数组
/*
* Pathlib support, takes a borrowed reference and returns a new one.
* The new object may be the same as the old.
*/
static inline PyObject *
NpyPath_PathlikeToFspath(PyObject *file)
{
// 检查 file 是否是 os_PathLike 实例,如果不是,则增加其引用计数并返回
if (!PyObject_IsInstance(file, npy_static_pydata.os_PathLike)) {
Py_INCREF(file);
return file;
}
// 如果 file 是 os_PathLike 实例,则调用 os_fspath 函数处理并返回其结果
return PyObject_CallFunctionObjArgs(npy_static_pydata.os_fspath,
file, NULL);
}
.\numpy\numpy\_core\src\multiarray\multiarraymodule.c
/*
Python Multiarray Module -- A useful collection of functions for creating and
using ndarrays
Original file
Copyright (c) 1995, 1996, 1997 Jim Hugunin, hugunin@mit.edu
Modified for numpy in 2005
Travis E. Oliphant
oliphant@ee.byu.edu
Brigham Young University
*/
NPY_NO_EXPORT int NPY_NUMUSERTYPES = 0;
/* Internal APIs */
/*
*****************************************************************************
** INCLUDE GENERATED CODE **
*****************************************************************************
*/
/* __ufunc_api.c define is the PyUFunc_API table: */
// 定义全局变量 NPY_NUMUSERTYPES,初始化为 0
NPY_NO_EXPORT int NPY_NUMUSERTYPES = 0;
// 声明初始化标量数学函数的函数
NPY_NO_EXPORT int initscalarmath(PyObject *);
// 声明设置矩阵乘法标志的函数,实现在 ufunc_object.c 中
NPY_NO_EXPORT int set_matmul_flags(PyObject *d);
// 声明在 umath/string_ufuncs.cpp/h 中实现的字符串比较函数
NPY_NO_EXPORT PyObject *
_umath_strings_richcompare(
PyArrayObject *self, PyArrayObject *other, int cmp_op, int rstrip);
// 定义设置遗留打印模式的函数
static PyObject *
set_legacy_print_mode(PyObject *NPY_UNUSED(self), PyObject *args)
{
// 解析参数,设置遗留打印模式
if (!PyArg_ParseTuple(args, "i", &npy_thread_unsafe_state.legacy_print_mode)) {
return NULL;
}
// 成功设置模式后返回 NULL
return NULL;
}
if (!npy_thread_unsafe_state.legacy_print_mode) {
npy_thread_unsafe_state.legacy_print_mode = INT_MAX;
}
Py_RETURN_NONE;
/*NUMPY_API
* Get Priority from object
*/
NPY_NO_EXPORT double
PyArray_GetPriority(PyObject *obj, double default_)
{
PyObject *ret;
double priority = NPY_PRIORITY;
// 检查对象是否为精确的 NumPy 数组对象
if (PyArray_CheckExact(obj)) {
return priority; // 如果是,则返回默认优先级
}
else if (PyArray_CheckAnyScalarExact(obj)) {
return NPY_SCALAR_PRIORITY; // 如果是精确的标量对象,则返回标量优先级
}
// 尝试在对象实例上查找特定属性 np.array_priority
ret = PyArray_LookupSpecial_OnInstance(obj, npy_interned_str.array_priority);
if (ret == NULL) {
if (PyErr_Occurred()) {
/* TODO[gh-14801]: propagate crashes during attribute access? */
PyErr_Clear(); // 如果出现错误,清除异常状态
}
return default_; // 返回默认优先级
}
// 将返回的属性值转换为双精度浮点数
priority = PyFloat_AsDouble(ret);
Py_DECREF(ret); // 减少属性对象的引用计数
if (error_converting(priority)) {
/* TODO[gh-14801]: propagate crashes for bad priority? */
PyErr_Clear(); // 如果转换出错,清除异常状态
return default_; // 返回默认优先级
}
return priority; // 返回计算得到的优先级
}
/*NUMPY_API
* Multiply a List of ints
*/
NPY_NO_EXPORT int
PyArray_MultiplyIntList(int const *l1, int n)
{
int s = 1;
// 逐个将列表中的整数相乘
while (n--) {
s *= (*l1++);
}
return s; // 返回乘积
}
/*NUMPY_API
* Multiply a List
*/
NPY_NO_EXPORT npy_intp
PyArray_MultiplyList(npy_intp const *l1, int n)
{
npy_intp s = 1;
// 逐个将列表中的整数相乘
while (n--) {
s *= (*l1++);
}
return s; // 返回乘积
}
/*NUMPY_API
* Multiply a List of Non-negative numbers with over-flow detection.
*/
NPY_NO_EXPORT npy_intp
PyArray_OverflowMultiplyList(npy_intp const *l1, int n)
{
npy_intp prod = 1;
int i;
// 逐个将列表中的非负数相乘,检测溢出
for (i = 0; i < n; i++) {
npy_intp dim = l1[i];
if (dim == 0) {
return 0; // 如果遇到零,直接返回零
}
if (npy_mul_sizes_with_overflow(&prod, prod, dim)) {
return -1; // 如果乘法溢出,返回负一
}
}
return prod; // 返回乘积
}
/*NUMPY_API
* Produce a pointer into array
*/
NPY_NO_EXPORT void *
PyArray_GetPtr(PyArrayObject *obj, npy_intp const* ind)
{
int n = PyArray_NDIM(obj);
npy_intp *strides = PyArray_STRIDES(obj);
char *dptr = PyArray_DATA(obj);
// 计算多维数组中指定索引的指针位置
while (n--) {
dptr += (*strides++) * (*ind++);
}
return (void *)dptr; // 返回指针
}
/*NUMPY_API
* Compare Lists
*/
NPY_NO_EXPORT int
PyArray_CompareLists(npy_intp const *l1, npy_intp const *l2, int n)
{
int i;
// 比较两个列表中的元素是否相等
for (i = 0; i < n; i++) {
if (l1[i] != l2[i]) {
return 0; // 如果有不相等的元素,返回零
}
}
return 1; // 如果所有元素都相等,返回一
}
/*
* simulates a C-style 1-3 dimensional array which can be accessed using
* ptr[i] or ptr[i][j] or ptr[i][j][k] -- requires pointer allocation
* for 2-d and 3-d.
*
* For 2-d and up, ptr is NOT equivalent to a statically defined
* 2-d or 3-d array. In particular, it cannot be passed into a
* function that requires a true pointer to a fixed-size array.
*/
/*NUMPY_API
* Simulate a C-array
* steals a reference to typedescr -- can be NULL
*/
NPY_NO_EXPORT int
PyArray_AsCArray(PyObject **op, void *ptr, npy_intp *dims, int nd,
PyArray_Descr* typedescr)
{
PyArrayObject *ap;
npy_intp n, m, i, j;
char **ptr2;
char ***ptr3;
if ((nd < 1) || (nd > 3)) {
PyErr_SetString(PyExc_ValueError,
"C arrays of only 1-3 dimensions available");
Py_XDECREF(typedescr);
return -1;
}
if ((ap = (PyArrayObject*)PyArray_FromAny(*op, typedescr, nd, nd,
NPY_ARRAY_CARRAY, NULL)) == NULL) {
return -1;
}
switch(nd) {
case 1:
*((char **)ptr) = PyArray_DATA(ap);
break;
case 2:
n = PyArray_DIMS(ap)[0];
ptr2 = (char **)PyArray_malloc(n * sizeof(char *));
if (!ptr2) {
PyErr_NoMemory();
return -1;
}
for (i = 0; i < n; i++) {
ptr2[i] = PyArray_BYTES(ap) + i*PyArray_STRIDES(ap)[0];
}
*((char ***)ptr) = ptr2;
break;
case 3:
n = PyArray_DIMS(ap)[0];
m = PyArray_DIMS(ap)[1];
ptr3 = (char ***)PyArray_malloc(n*(m+1) * sizeof(char *));
if (!ptr3) {
PyErr_NoMemory();
return -1;
}
for (i = 0; i < n; i++) {
ptr3[i] = (char **) &ptr3[n + m * i];
for (j = 0; j < m; j++) {
ptr3[i][j] = PyArray_BYTES(ap) + i*PyArray_STRIDES(ap)[0] + j*PyArray_STRIDES(ap)[1];
}
}
*((char ****)ptr) = ptr3;
}
if (nd) {
memcpy(dims, PyArray_DIMS(ap), nd*sizeof(npy_intp));
}
*op = (PyObject *)ap;
return 0;
/*NUMPY_API
* Free pointers created if As2D is called
*/
NPY_NO_EXPORT int
PyArray_Free(PyObject *op, void *ptr)
{
PyArrayObject *ap = (PyArrayObject *)op;
// 如果数组维度小于1或大于3,则返回错误
if ((PyArray_NDIM(ap) < 1) || (PyArray_NDIM(ap) > 3)) {
return -1;
}
// 如果数组维度大于等于2,则释放指针
if (PyArray_NDIM(ap) >= 2) {
PyArray_free(ptr);
}
// 减少数组对象的引用计数
Py_DECREF(ap);
return 0;
}
/*
* Get the ndarray subclass with the highest priority
*/
NPY_NO_EXPORT PyTypeObject *
PyArray_GetSubType(int narrays, PyArrayObject **arrays) {
PyTypeObject *subtype = &PyArray_Type;
double priority = NPY_PRIORITY;
int i;
/* 获取具有最高优先级的子类 */
for (i = 0; i < narrays; ++i) {
if (Py_TYPE(arrays[i]) != subtype) {
double pr = PyArray_GetPriority((PyObject *)(arrays[i]), 0.0);
// 如果当前数组的优先级高于已知的最高优先级,则更新子类
if (pr > priority) {
priority = pr;
subtype = Py_TYPE(arrays[i]);
}
}
}
return subtype;
}
/*
* Concatenates a list of ndarrays.
*/
NPY_NO_EXPORT PyArrayObject *
PyArray_ConcatenateArrays(int narrays, PyArrayObject **arrays, int axis,
PyArrayObject* ret, PyArray_Descr *dtype,
NPY_CASTING casting)
{
int iarrays, idim, ndim;
npy_intp shape[NPY_MAXDIMS];
PyArrayObject_fields *sliding_view = NULL;
// 至少需要一个数组来进行连接
if (narrays <= 0) {
PyErr_SetString(PyExc_ValueError,
"need at least one array to concatenate");
return NULL;
}
// 所有数组必须具有相同的维度
ndim = PyArray_NDIM(arrays[0]);
if (ndim == 0) {
PyErr_SetString(PyExc_ValueError,
"zero-dimensional arrays cannot be concatenated");
return NULL;
}
// 处理标准的负索引
if (check_and_adjust_axis(&axis, ndim) < 0) {
return NULL;
}
/*
* 从第一个数组的形状开始计算最终连接的形状
*/
memcpy(shape, PyArray_SHAPE(arrays[0]), ndim * sizeof(shape[0]));
for (iarrays = 1; iarrays < narrays; ++iarrays) {
npy_intp *arr_shape;
// 检查当前数组与第一个数组的维度是否一致
if (PyArray_NDIM(arrays[iarrays]) != ndim) {
PyErr_Format(PyExc_ValueError,
"all the input arrays must have same number of "
"dimensions, but the array at index %d has %d "
"dimension(s) and the array at index %d has %d "
"dimension(s)",
0, ndim, iarrays, PyArray_NDIM(arrays[iarrays]));
return NULL;
}
// 获取当前数组的形状
arr_shape = PyArray_SHAPE(arrays[iarrays]);
// 遍历每个维度
for (idim = 0; idim < ndim; ++idim) {
/* Build up the size of the concatenation axis */
// 如果当前维度是连接轴(axis),增加该维度的大小
if (idim == axis) {
shape[idim] += arr_shape[idim];
}
/* Validate that the rest of the dimensions match */
// 否则,验证当前维度与第一个数组的对应维度是否相等
else if (shape[idim] != arr_shape[idim]) {
PyErr_Format(PyExc_ValueError,
"all the input array dimensions except for the "
"concatenation axis must match exactly, but "
"along dimension %d, the array at index %d has "
"size %d and the array at index %d has size %d",
idim, 0, shape[idim], iarrays, arr_shape[idim]);
return NULL;
}
}
}
// 如果输出数组 ret 不为空,进行进一步验证
if (ret != NULL) {
assert(dtype == NULL);
// 检查输出数组的维度是否正确
if (PyArray_NDIM(ret) != ndim) {
PyErr_SetString(PyExc_ValueError,
"Output array has wrong dimensionality");
return NULL;
}
// 检查输出数组的形状是否与期望的形状相符
if (!PyArray_CompareLists(shape, PyArray_SHAPE(ret), ndim)) {
PyErr_SetString(PyExc_ValueError,
"Output array is the wrong shape");
return NULL;
}
// 增加输出数组的引用计数
Py_INCREF(ret);
}
else {
npy_intp s, strides[NPY_MAXDIMS];
int strideperm[NPY_MAXDIMS];
/* 获取数组的优先子类型 */
PyTypeObject *subtype = PyArray_GetSubType(narrays, arrays);
/* 找到合并后数组的描述符 */
PyArray_Descr *descr = PyArray_FindConcatenationDescriptor(
narrays, arrays, dtype);
if (descr == NULL) {
return NULL;
}
/*
* 计算需要对步幅进行的排列,以匹配输入数组的内存布局,
* 使用与 NpyIter 类似的歧义解析规则。
*/
PyArray_CreateMultiSortedStridePerm(narrays, arrays, ndim, strideperm);
s = descr->elsize;
for (idim = ndim-1; idim >= 0; --idim) {
int iperm = strideperm[idim];
strides[iperm] = s;
s *= shape[iperm];
}
/* 分配结果数组的空间。这里会窃取 'dtype' 的引用。 */
ret = (PyArrayObject *)PyArray_NewFromDescr_int(
subtype, descr, ndim, shape, strides, NULL, 0, NULL,
NULL, _NPY_ARRAY_ALLOW_EMPTY_STRING);
if (ret == NULL) {
return NULL;
}
}
/*
* 创建一个视图,用于在 ret 中滑动以赋值各个输入数组。
*/
sliding_view = (PyArrayObject_fields *)PyArray_View(ret,
NULL, &PyArray_Type);
if (sliding_view == NULL) {
Py_DECREF(ret);
return NULL;
}
for (iarrays = 0; iarrays < narrays; ++iarrays) {
/* 设置维度以匹配输入数组的维度 */
sliding_view->dimensions[axis] = PyArray_SHAPE(arrays[iarrays])[axis];
/* 复制当前数组的数据 */
if (PyArray_AssignArray((PyArrayObject *)sliding_view, arrays[iarrays],
NULL, casting) < 0) {
Py_DECREF(sliding_view);
Py_DECREF(ret);
return NULL;
}
/* 滑动到下一个窗口的起始位置 */
sliding_view->data += sliding_view->dimensions[axis] *
sliding_view->strides[axis];
}
Py_DECREF(sliding_view);
return ret;
/*
* Concatenates a list of ndarrays, flattening each in the specified order.
*/
NPY_NO_EXPORT PyArrayObject *
PyArray_ConcatenateFlattenedArrays(int narrays, PyArrayObject **arrays,
NPY_ORDER order, PyArrayObject *ret,
PyArray_Descr *dtype, NPY_CASTING casting,
npy_bool casting_not_passed)
{
int iarrays;
npy_intp shape = 0;
PyArrayObject_fields *sliding_view = NULL;
// 检查输入的数组数量是否合法,至少需要一个数组
if (narrays <= 0) {
PyErr_SetString(PyExc_ValueError,
"need at least one array to concatenate");
return NULL;
}
/*
* 计算最终连接后的数组形状,从第一个数组的形状开始计算。
*/
for (iarrays = 0; iarrays < narrays; ++iarrays) {
shape += PyArray_SIZE(arrays[iarrays]);
/* 检查是否溢出 */
if (shape < 0) {
PyErr_SetString(PyExc_ValueError,
"total number of elements "
"too large to concatenate");
return NULL;
}
}
int out_passed = 0;
// 如果已经提供了输出数组ret,则验证其合法性
if (ret != NULL) {
assert(dtype == NULL);
out_passed = 1;
// 输出数组必须是一维的
if (PyArray_NDIM(ret) != 1) {
PyErr_SetString(PyExc_ValueError,
"Output array must be 1D");
return NULL;
}
// 输出数组的大小必须与计算得到的shape相等
if (shape != PyArray_SIZE(ret)) {
PyErr_SetString(PyExc_ValueError,
"Output array is the wrong size");
return NULL;
}
// 增加输出数组的引用计数
Py_INCREF(ret);
}
else {
npy_intp stride;
/* 获取数组的优先子类型 */
PyTypeObject *subtype = PyArray_GetSubType(narrays, arrays);
// 查找连接数组时需要的描述符
PyArray_Descr *descr = PyArray_FindConcatenationDescriptor(
narrays, arrays, dtype);
if (descr == NULL) {
return NULL;
}
stride = descr->elsize;
/*
* 分配结果数组的内存空间。这里会使用描述符来分配,并且会偷窃描述符的引用。
*/
ret = (PyArrayObject *)PyArray_NewFromDescr_int(
subtype, descr, 1, &shape, &stride, NULL, 0, NULL,
NULL, _NPY_ARRAY_ALLOW_EMPTY_STRING);
if (ret == NULL) {
return NULL;
}
assert(PyArray_DESCR(ret) == descr);
}
/*
* 创建一个视图,通过该视图可以在结果数组ret中滑动并逐个赋值输入数组。
*/
sliding_view = (PyArrayObject_fields *)PyArray_View(ret,
NULL, &PyArray_Type);
if (sliding_view == NULL) {
Py_DECREF(ret);
return NULL;
}
// 是否需要给出弃用警告,仅用于第一个输入数组
int give_deprecation_warning = 1; /* To give warning for just one input array. */
for (iarrays = 0; iarrays < narrays; ++iarrays) {
/* Adjust the window dimensions for this array */
// 更新滑动视图的第一个维度为当前数组的大小
sliding_view->dimensions[0] = PyArray_SIZE(arrays[iarrays]);
if (!PyArray_CanCastArrayTo(
arrays[iarrays], PyArray_DESCR(ret), casting)) {
/* This should be an error, but was previously allowed here. */
// 如果无法将数组 `arrays[iarrays]` 强制转换为 `ret` 的数据类型,则处理错误
if (casting_not_passed && out_passed) {
/* NumPy 1.20, 2020-09-03 */
// 如果需要发出弃用警告,并且发出警告时出现错误,则清理资源并返回 NULL
if (give_deprecation_warning && DEPRECATE(
"concatenate() with `axis=None` will use same-kind "
"casting by default in the future. Please use "
"`casting='unsafe'` to retain the old behaviour. "
"In the future this will be a TypeError.") < 0) {
Py_DECREF(sliding_view);
Py_DECREF(ret);
return NULL;
}
give_deprecation_warning = 0;
}
else {
// 设置类型转换错误并返回 NULL
npy_set_invalid_cast_error(
PyArray_DESCR(arrays[iarrays]), PyArray_DESCR(ret),
casting, PyArray_NDIM(arrays[iarrays]) == 0);
Py_DECREF(sliding_view);
Py_DECREF(ret);
return NULL;
}
}
/* Copy the data for this array */
// 复制当前数组的数据到滑动视图
if (PyArray_CopyAsFlat((PyArrayObject *)sliding_view, arrays[iarrays],
order) < 0) {
// 如果复制失败,则清理资源并返回 NULL
Py_DECREF(sliding_view);
Py_DECREF(ret);
return NULL;
}
/* Slide to the start of the next window */
// 将滑动视图的数据指针滑动到下一个窗口的起始位置
sliding_view->data +=
sliding_view->strides[0] * PyArray_SIZE(arrays[iarrays]);
}
// 释放滑动视图的引用并返回结果数组
Py_DECREF(sliding_view);
return ret;
/**
* Implementation for np.concatenate
*
* @param op Sequence of arrays to concatenate
* @param axis Axis to concatenate along
* @param ret output array to fill
* @param dtype Forced output array dtype (cannot be combined with ret)
* @param casting Casting mode used
* @param casting_not_passed Deprecation helper
*/
NPY_NO_EXPORT PyObject *
PyArray_ConcatenateInto(PyObject *op,
int axis, PyArrayObject *ret, PyArray_Descr *dtype,
NPY_CASTING casting, npy_bool casting_not_passed)
{
int iarrays, narrays;
PyArrayObject **arrays;
// 检查输入参数op是否为序列类型,如果不是则返回类型错误
if (!PySequence_Check(op)) {
PyErr_SetString(PyExc_TypeError,
"The first input argument needs to be a sequence");
return NULL;
}
// 如果同时提供了ret和dtype参数,则返回类型错误
if (ret != NULL && dtype != NULL) {
PyErr_SetString(PyExc_TypeError,
"concatenate() only takes `out` or `dtype` as an "
"argument, but both were provided.");
return NULL;
}
/* Convert the input list into arrays */
// 获取序列op的长度,如果获取失败则返回NULL
narrays = PySequence_Size(op);
if (narrays < 0) {
return NULL;
}
// 分配存储PyArrayObject指针的数组空间
arrays = PyArray_malloc(narrays * sizeof(arrays[0]));
if (arrays == NULL) {
PyErr_NoMemory();
return NULL;
}
// 遍历序列op中的每个元素,将其转换为PyArrayObject
for (iarrays = 0; iarrays < narrays; ++iarrays) {
PyObject *item = PySequence_GetItem(op, iarrays);
if (item == NULL) {
// 如果获取元素失败,则记录当前处理到的元素个数,跳转到失败处理部分
narrays = iarrays;
goto fail;
}
// 将Python对象item转换为PyArrayObject
arrays[iarrays] = (PyArrayObject *)PyArray_FROM_O(item);
if (arrays[iarrays] == NULL) {
// 如果转换失败,则释放前面成功转换的对象并记录失败位置,跳转到失败处理部分
Py_DECREF(item);
narrays = iarrays;
goto fail;
}
// 标记item对象为临时数组,用于在处理时避免误操作
npy_mark_tmp_array_if_pyscalar(item, arrays[iarrays], NULL);
Py_DECREF(item);
}
// 根据axis参数确定调用不同的数组拼接函数
if (axis == NPY_RAVEL_AXIS) {
ret = PyArray_ConcatenateFlattenedArrays(
narrays, arrays, NPY_CORDER, ret, dtype,
casting, casting_not_passed);
}
else {
ret = PyArray_ConcatenateArrays(
narrays, arrays, axis, ret, dtype, casting);
}
// 释放分配的PyArrayObject指针数组及其元素
for (iarrays = 0; iarrays < narrays; ++iarrays) {
Py_DECREF(arrays[iarrays]);
}
PyArray_free(arrays);
// 返回拼接后的结果数组对象
return (PyObject *)ret;
fail:
/* 'narrays' was set to how far we got in the conversion */
// 处理转换失败时释放已成功转换的对象,并释放数组空间
for (iarrays = 0; iarrays < narrays; ++iarrays) {
Py_DECREF(arrays[iarrays]);
}
PyArray_free(arrays);
return NULL;
}
/*NUMPY_API
* Concatenate
*
* Concatenate an arbitrary Python sequence into an array.
* op is a python object supporting the sequence interface.
* Its elements will be concatenated together to form a single
* multidimensional array. If axis is NPY_MAXDIMS or bigger, then
* each sequence object will be flattened before concatenation
*/
NPY_NO_EXPORT PyObject *
PyArray_Concatenate(PyObject *op, int axis)
{
// 保留旧版的类型转换行为
NPY_CASTING casting;
// 如果axis大于或等于NPY_MAXDIMS,则设置类型转换模式为NPY_UNSAFE_CASTING
if (axis >= NPY_MAXDIMS) {
casting = NPY_UNSAFE_CASTING;
}
else {
casting = NPY_SAME_KIND_CASTING;
}
return PyArray_ConcatenateInto(
op, axis, NULL, NULL, casting, 0);
}
static int
_signbit_set(PyArrayObject *arr)
{
static char bitmask = (char) 0x80; // 定义一个静态字符变量,用于表示最高位为1的位掩码
char *ptr; /* points to the npy_byte to test */ // 指向要测试的 npy_byte 的指针
char byteorder; // 存储数组的字节顺序信息
int elsize; // 存储数组元素的大小
elsize = PyArray_ITEMSIZE(arr); // 获取数组元素的大小
byteorder = PyArray_DESCR(arr)->byteorder; // 获取数组的字节顺序
ptr = PyArray_DATA(arr); // 获取数组数据的指针
if (elsize > 1 &&
(byteorder == NPY_LITTLE ||
(byteorder == NPY_NATIVE &&
PyArray_ISNBO(NPY_LITTLE)))) {
ptr += elsize - 1; // 如果数组元素大小大于1且字节顺序为小端或者本机字节顺序是小端并且数组也是小端,将指针移动到倒数第二个元素
}
return ((*ptr & bitmask) != 0); // 返回指针指向的字节与位掩码进行按位与运算后的结果是否为非零
}
/*NUMPY_API
* ScalarKind
*
* Returns the scalar kind of a type number, with an
* optional tweak based on the scalar value itself.
* If no scalar is provided, it returns INTPOS_SCALAR
* for both signed and unsigned integers, otherwise
* it checks the sign of any signed integer to choose
* INTNEG_SCALAR when appropriate.
*/
NPY_NO_EXPORT NPY_SCALARKIND
PyArray_ScalarKind(int typenum, PyArrayObject **arr)
{
NPY_SCALARKIND ret = NPY_NOSCALAR; // 初始化返回值,默认为 NPY_NOSCALAR
if ((unsigned int)typenum < NPY_NTYPES_LEGACY) {
ret = _npy_scalar_kinds_table[typenum]; // 从预定义的标量类型表中获取标量类型
/* Signed integer types are INTNEG in the table */
if (ret == NPY_INTNEG_SCALAR) { // 如果标量类型为负整数
if (!arr || !_signbit_set(*arr)) { // 如果没有提供数组或者数组的最高位不是1
ret = NPY_INTPOS_SCALAR; // 返回正整数标量类型
}
}
} else if (PyTypeNum_ISUSERDEF(typenum)) { // 如果类型号是用户定义的类型
PyArray_Descr* descr = PyArray_DescrFromType(typenum); // 根据类型号获取数据类型描述符
if (PyDataType_GetArrFuncs(descr)->scalarkind) {
ret = PyDataType_GetArrFuncs(descr)->scalarkind((arr ? *arr : NULL)); // 获取数据类型描述符的标量类型
}
Py_DECREF(descr); // 减少数据类型描述符的引用计数
}
return ret; // 返回标量类型
}
/*NUMPY_API
*
* Determines whether the data type 'thistype', with
* scalar kind 'scalar', can be coerced into 'neededtype'.
*/
NPY_NO_EXPORT int
PyArray_CanCoerceScalar(int thistype, int neededtype,
NPY_SCALARKIND scalar)
{
PyArray_Descr* from;
int *castlist;
/* If 'thistype' is not a scalar, it must be safely castable */
if (scalar == NPY_NOSCALAR) {
return PyArray_CanCastSafely(thistype, neededtype); // 如果不是标量类型,直接检查是否能够安全地转换
}
if ((unsigned int)neededtype < NPY_NTYPES_LEGACY) {
NPY_SCALARKIND neededscalar;
if (scalar == NPY_OBJECT_SCALAR) {
return PyArray_CanCastSafely(thistype, neededtype); // 如果目标类型是对象类型标量,直接检查是否能够安全地转换
}
/*
* The lookup table gives us exactly what we need for
* this comparison, which PyArray_ScalarKind would not.
*
* The rule is that positive scalars can be coerced
* to a signed ints, but negative scalars cannot be coerced
* to unsigned ints.
* _npy_scalar_kinds_table[int]==NEGINT > POSINT,
* so 1 is returned, but
* _npy_scalar_kinds_table[uint]==POSINT < NEGINT,
* so 0 is returned, as required.
*
*/
neededscalar = _npy_scalar_kinds_table[neededtype]; // 获取目标类型的标量类型
if (neededscalar >= scalar) {
return 1; // 如果目标标量类型大于等于当前标量类型,返回1
}
if (!PyTypeNum_ISUSERDEF(thistype)) {
return 0; // 如果当前类型不是用户定义的类型,返回0
}
}
这是一段代码的结尾,表示一个函数或者一个代码块的结束。
from = PyArray_DescrFromType(thistype);
调用 `PyArray_DescrFromType` 函数,根据 `thistype` 参数获取一个描述符对象,并将其赋值给 `from` 变量。
if (PyDataType_GetArrFuncs(from)->cancastscalarkindto
检查从描述符对象 `from` 获取的数组函数集合中是否存在 `cancastscalarkindto` 字段或属性。
&& (castlist = PyDataType_GetArrFuncs(from)->cancastscalarkindto[scalar])) {
如果 `cancastscalarkindto` 存在,则将其与 `scalar` 索引相关联的 `castlist` 变量进行比较。
while (*castlist != NPY_NOTYPE) {
进入一个循环,该循环将检查 `castlist` 中的每个元素,直到遇到 `NPY_NOTYPE` 结束循环。
if (*castlist++ == neededtype) {
检查当前 `castlist` 指向的元素是否等于 `neededtype`。
Py_DECREF(from);
如果找到了匹配的 `neededtype`,则释放 `from` 对象,并返回 `1` 表示找到匹配。
return 1;
}
}
}
结束循环后,如果没有找到匹配的 `neededtype`,继续执行下面的代码。
Py_DECREF(from);
在函数返回之前,释放 `from` 对象。
return 0;
如果没有找到匹配的 `neededtype`,则返回 `0` 表示未找到匹配。
}
/* Could perhaps be redone to not make contiguous arrays */
/*NUMPY_API
* Numeric.innerproduct(a,v)
*/
NPY_NO_EXPORT PyObject *
PyArray_InnerProduct(PyObject *op1, PyObject *op2)
{
PyArrayObject *ap1 = NULL; // 定义数组对象指针 ap1,初始化为 NULL
PyArrayObject *ap2 = NULL; // 定义数组对象指针 ap2,初始化为 NULL
int typenum; // 定义整型变量 typenum,用于存储数组元素的数据类型编号
PyArray_Descr *typec = NULL; // 定义数组描述符指针 typec,初始化为 NULL
PyObject* ap2t = NULL; // 定义 Python 对象指针 ap2t,初始化为 NULL
npy_intp dims[NPY_MAXDIMS]; // 定义整型数组 dims,用于存储数组维度信息
PyArray_Dims newaxes = {dims, 0}; // 定义 PyArray_Dims 结构 newaxes,并初始化其维度信息为 dims,长度为 0
int i; // 定义整型变量 i,用于循环计数
PyObject* ret = NULL; // 定义 Python 对象指针 ret,初始化为 NULL
typenum = PyArray_ObjectType(op1, NPY_NOTYPE); // 调用 PyArray_ObjectType 函数获取 op1 的数组元素数据类型编号
if (typenum == NPY_NOTYPE) { // 如果获取的数据类型编号为 NPY_NOTYPE,返回 NULL
return NULL;
}
typenum = PyArray_ObjectType(op2, typenum); // 调用 PyArray_ObjectType 函数获取 op2 的数组元素数据类型编号,并与之前的 typenum 进行匹配
if (typenum == NPY_NOTYPE) { // 如果获取的数据类型编号为 NPY_NOTYPE,返回 NULL
return NULL;
}
typec = PyArray_DescrFromType(typenum); // 根据 typenum 获取数组描述符 typec
if (typec == NULL) { // 如果获取的数组描述符为 NULL
if (!PyErr_Occurred()) { // 如果没有发生 Python 异常
PyErr_SetString(PyExc_TypeError,
"Cannot find a common data type."); // 设置类型错误异常信息
}
goto fail; // 跳转到 fail 标签处,执行清理操作
}
Py_INCREF(typec); // 增加 typec 的引用计数
ap1 = (PyArrayObject *)PyArray_FromAny(op1, typec, 0, 0,
NPY_ARRAY_ALIGNED, NULL); // 根据 op1 和 typec 创建 PyArrayObject 对象 ap1
if (ap1 == NULL) { // 如果创建的 ap1 为 NULL
Py_DECREF(typec); // 减少 typec 的引用计数
goto fail; // 跳转到 fail 标签处,执行清理操作
}
ap2 = (PyArrayObject *)PyArray_FromAny(op2, typec, 0, 0,
NPY_ARRAY_ALIGNED, NULL); // 根据 op2 和 typec 创建 PyArrayObject 对象 ap2
if (ap2 == NULL) { // 如果创建的 ap2 为 NULL
goto fail; // 跳转到 fail 标签处,执行清理操作
}
newaxes.len = PyArray_NDIM(ap2); // 设置 newaxes 结构体的长度为 ap2 的维度数
if ((PyArray_NDIM(ap1) >= 1) && (newaxes.len >= 2)) { // 如果 ap1 的维度大于等于 1 并且 newaxes 的长度大于等于 2
for (i = 0; i < newaxes.len - 2; i++) { // 循环遍历 newaxes 长度减去 2 的次数
dims[i] = (npy_intp)i; // 设置 dims 数组的值为循环变量 i 的值
}
dims[newaxes.len - 2] = newaxes.len - 1; // 设置 dims 数组倒数第二个元素为 newaxes 长度减 1 的值
dims[newaxes.len - 1] = newaxes.len - 2; // 设置 dims 数组最后一个元素为 newaxes 长度减 2 的值
ap2t = PyArray_Transpose(ap2, &newaxes); // 对 ap2 进行转置操作,结果存储在 ap2t 中
if (ap2t == NULL) { // 如果转置操作返回 NULL
goto fail; // 跳转到 fail 标签处,执行清理操作
}
}
else { // 如果 ap1 的维度小于 1 或者 newaxes 的长度小于 2
ap2t = (PyObject *)ap2; // 直接将 ap2 赋给 ap2t
Py_INCREF(ap2); // 增加 ap2 的引用计数
}
ret = PyArray_MatrixProduct2((PyObject *)ap1, ap2t, NULL); // 调用 PyArray_MatrixProduct2 函数进行矩阵乘法运算,结果存储在 ret 中
if (ret == NULL) { // 如果 ret 为 NULL
goto fail; // 跳转到 fail 标签处,执行清理操作
}
Py_DECREF(ap1); // 减少 ap1 的引用计数
Py_DECREF(ap2); // 减少 ap2 的引用计数
Py_DECREF(ap2t); // 减少 ap2t 的引用计数
return ret; // 返回 ret
fail: // 定义 fail 标签处,用于处理错误清理操作
Py_XDECREF(ap1); // 安全地减少 ap1 的引用计数
Py_XDECREF(ap2); // 安全地减少 ap2 的引用计数
Py_XDECREF(ap2t); // 安全地减少 ap2t 的引用计数
Py_XDECREF(ret); // 安全地减少 ret 的引用计数
return NULL; // 返回 NULL
}
/*NUMPY_API
* Numeric.matrixproduct(a,v)
* just like inner product but does the swapaxes stuff on the fly
*/
NPY_NO_EXPORT PyObject *
PyArray_MatrixProduct(PyObject *op1, PyObject *op2)
{
return PyArray_MatrixProduct2(op1, op2, NULL); // 调用 PyArray_MatrixProduct2 函数进行矩阵乘法运算,结果返回
}
/*NUMPY_API
* Numeric.matrixproduct2(a,v,out)
* just like inner product but does the swapaxes stuff on the fly
*/
NPY_NO_EXPORT PyObject *
PyArray_MatrixProduct2(PyObject *op1, PyObject *op2, PyArrayObject* out)
{
PyArrayObject *ap1, *ap2, *out_buf = NULL, *result = NULL; // 定义多个 PyArrayObject 指针,初始化为 NULL
PyArrayIterObject *it1, *it2; // 定义 PyArrayIterObject 迭代器指针
npy_intp i, j, l; // 定义多个整型变量
int typenum, nd, axis, matchDim; // 定义多个整型变量
npy_intp is1, is2, os; // 定义多个整型变量
char *op; // 定义字符指针 op
npy_intp dimensions[NPY_MAXDIMS]; // 定义整型数组 dimensions,用于存储数组维度信息
PyArray_DotFunc *dot; // 定义 PyArray_DotFunc 结构指针 dot
PyArray_Descr *typec = NULL; // 定义数组描述符指针 typec,初始化为 NULL
NPY_BEGIN_THREADS_DEF; // 定义多线程宏
typenum = PyArray_ObjectType(op1, NPY_NOTYPE); // 调用 PyArray_ObjectType 函数获取 op1 的数组元素数据类型编号
if (typenum == NPY_NOTYPE) { // 如果获取的数据类型编号为 NPY_NOTYPE,返回 NULL
return NULL;
}
typenum = PyArray_ObjectType(op2, typenum);
if (typenum == NPY_NOTYPE) {
return NULL;
}
typec = PyArray_DescrFromType(typenum);
if (typec == NULL) {
if (!PyErr_Occurred()) {
PyErr_SetString(PyExc_TypeError,
"Cannot find a common data type.");
}
return NULL;
}
Py_INCREF(typec);
ap1 = (PyArrayObject *)PyArray_FromAny(op1, typec, 0, 0,
NPY_ARRAY_ALIGNED, NULL);
if (ap1 == NULL) {
Py_DECREF(typec);
return NULL;
}
ap2 = (PyArrayObject *)PyArray_FromAny(op2, typec, 0, 0,
NPY_ARRAY_ALIGNED, NULL);
if (ap2 == NULL) {
Py_DECREF(ap1);
return NULL;
}
// 检查是否定义了 CBLAS,并且数组维度都不超过2,且数据类型为双精度、单精度或复数类型之一
if (PyArray_NDIM(ap1) <= 2 && PyArray_NDIM(ap2) <= 2 &&
(NPY_DOUBLE == typenum || NPY_CDOUBLE == typenum ||
NPY_FLOAT == typenum || NPY_CFLOAT == typenum)) {
// 调用 cblas_matrixproduct 函数进行矩阵乘积计算
return cblas_matrixproduct(typenum, ap1, ap2, out);
}
// 处理当 ap1 或 ap2 至少有一个是零维数组的情况
if (PyArray_NDIM(ap1) == 0 || PyArray_NDIM(ap2) == 0) {
// 调用 multiply 函数计算两个数组的乘积,并返回结果
PyObject *mul_res = PyObject_CallFunctionObjArgs(
n_ops.multiply, ap1, ap2, out, NULL);
// 减少数组 ap1 和 ap2 的引用计数
Py_DECREF(ap1);
Py_DECREF(ap2);
// 返回乘积结果
return mul_res;
}
// 获取 ap1 最后一个维度的大小
l = PyArray_DIMS(ap1)[PyArray_NDIM(ap1) - 1];
// 确定匹配维度 matchDim 的值
if (PyArray_NDIM(ap2) > 1) {
matchDim = PyArray_NDIM(ap2) - 2;
} else {
matchDim = 0;
}
// 检查维度是否匹配
if (PyArray_DIMS(ap2)[matchDim] != l) {
// 引发维度不匹配错误,并跳转到 fail 标签处理错误
dot_alignment_error(ap1, PyArray_NDIM(ap1) - 1, ap2, matchDim);
goto fail;
}
// 计算输出数组的维度数
nd = PyArray_NDIM(ap1) + PyArray_NDIM(ap2) - 2;
// 检查是否超过最大维度限制
if (nd > NPY_MAXDIMS) {
PyErr_SetString(PyExc_ValueError, "dot: too many dimensions in result");
goto fail;
}
// 初始化 dimensions 数组以存储输出数组的维度信息
j = 0;
for (i = 0; i < PyArray_NDIM(ap1) - 1; i++) {
dimensions[j++] = PyArray_DIMS(ap1)[i];
}
for (i = 0; i < PyArray_NDIM(ap2) - 2; i++) {
dimensions[j++] = PyArray_DIMS(ap2)[i];
}
if (PyArray_NDIM(ap2) > 1) {
dimensions[j++] = PyArray_DIMS(ap2)[PyArray_NDIM(ap2)-1];
}
// 获取数组 ap1 和 ap2 的步长信息
is1 = PyArray_STRIDES(ap1)[PyArray_NDIM(ap1)-1];
is2 = PyArray_STRIDES(ap2)[matchDim];
/* 选择要返回的子类型 */
// 根据参数创建新的输出数组,并返回其数据缓冲区
out_buf = new_array_for_sum(ap1, ap2, out, nd, dimensions, typenum, &result);
if (out_buf == NULL) {
goto fail;
}
/* 确保当 ap1 和 ap2 均为空数组时,返回全零数组 */
// 如果 ap1 和 ap2 均为空数组,则将输出数组设为全零数组
if (PyArray_SIZE(ap1) == 0 && PyArray_SIZE(ap2) == 0) {
if (PyArray_AssignZero(out_buf, NULL) < 0) {
goto fail;
}
}
// 获取输出数组的 dot 函数
dot = PyDataType_GetArrFuncs(PyArray_DESCR(out_buf))->dotfunc;
if (dot == NULL) {
// 如果 dot 函数为 NULL,则引发错误并跳转到 fail 标签处理错误
PyErr_SetString(PyExc_ValueError,
"dot not available for this type");
goto fail;
}
// 初始化输出数组的数据指针和每个元素的字节大小
op = PyArray_DATA(out_buf);
os = PyArray_ITEMSIZE(out_buf);
// 设置 axis 为 ap1 最后一个维度的索引
axis = PyArray_NDIM(ap1)-1;
// 创建迭代器 it1,用于遍历除了最后一个维度外的所有维度
it1 = (PyArrayIterObject *)
PyArray_IterAllButAxis((PyObject *)ap1, &axis);
if (it1 == NULL) {
goto fail;
}
// 创建迭代器 it2,用于遍历除了匹配维度外的所有维度
it2 = (PyArrayIterObject *)
PyArray_IterAllButAxis((PyObject *)ap2, &matchDim);
if (it2 == NULL) {
Py_DECREF(it1);
goto fail;
}
// 开始多线程处理,保护 ap2 数组的描述信息
NPY_BEGIN_THREADS_DESCR(PyArray_DESCR(ap2));
while (it1->index < it1->size) {
while (it2->index < it2->size) {
// 对每对迭代器指向的数据执行 dot 操作
dot(it1->dataptr, is1, it2->dataptr, is2, op, l, NULL);
// 更新输出数据指针到下一个位置
op += os;
// 移动 it2 迭代器到下一个元素
PyArray_ITER_NEXT(it2);
}
// 移动 it1 迭代器到下一个元素
PyArray_ITER_NEXT(it1);
// 重置 it2 迭代器到起始位置
PyArray_ITER_RESET(it2);
}
// 结束多线程处理,释放 ap2 数组的描述信息
NPY_END_THREADS_DESCR(PyArray_DESCR(ap2));
// 减少迭代器 it1 和 it2 的引用计数
Py_DECREF(it1);
Py_DECREF(it2);
// 检查是否有 Python 异常发生,如果有,则跳转到 fail 标签处理异常
if (PyErr_Occurred()) {
/* 仅适用于 OBJECT 类型的数组 */
goto fail;
}
// 减少数组 ap1 的引用计数
Py_DECREF(ap1);
// 释放对象引用,减少 `ap2` 的引用计数
Py_DECREF(ap2);
// 如果需要,触发将 `out_buf` 中的数据复制回 `result`
PyArray_ResolveWritebackIfCopy(out_buf);
// 释放对象引用,减少 `out_buf` 的引用计数
Py_DECREF(out_buf);
// 返回 `result` 对象作为 Python 对象的指针
return (PyObject *)result;
fail:
// 释放指针 ap1 所指向的对象,减少其引用计数
Py_XDECREF(ap1);
// 释放指针 ap2 所指向的对象,减少其引用计数
Py_XDECREF(ap2);
// 释放指针 out_buf 所指向的对象,减少其引用计数
Py_XDECREF(out_buf);
// 释放指针 result 所指向的对象,减少其引用计数
Py_XDECREF(result);
// 返回 NULL 指针,表示函数执行失败
return NULL;
}
/*
* Implementation which is common between PyArray_Correlate
* and PyArray_Correlate2.
*
* inverted is set to 1 if computed correlate(ap2, ap1), 0 otherwise
*/
static PyArrayObject*
_pyarray_correlate(PyArrayObject *ap1, PyArrayObject *ap2, int typenum,
int mode, int *inverted)
{
PyArrayObject *ret;
npy_intp length;
npy_intp i, n1, n2, n, n_left, n_right;
npy_intp is1, is2, os;
char *ip1, *ip2, *op;
PyArray_DotFunc *dot;
NPY_BEGIN_THREADS_DEF;
// 获取数组 ap1 和 ap2 的长度
n1 = PyArray_DIMS(ap1)[0];
n2 = PyArray_DIMS(ap2)[0];
// 如果数组 ap1 长度为 0,抛出异常并返回 NULL 指针
if (n1 == 0) {
PyErr_SetString(PyExc_ValueError, "first array argument cannot be empty");
return NULL;
}
// 如果数组 ap2 长度为 0,抛出异常并返回 NULL 指针
if (n2 == 0) {
PyErr_SetString(PyExc_ValueError, "second array argument cannot be empty");
return NULL;
}
// 如果数组 ap1 长度小于数组 ap2,交换它们的引用,设置 *inverted 为 1
if (n1 < n2) {
ret = ap1;
ap1 = ap2;
ap2 = ret;
ret = NULL;
i = n1;
n1 = n2;
n2 = i;
*inverted = 1;
} else {
*inverted = 0;
}
length = n1;
n = n2;
switch(mode) {
// 根据 mode 的值设置相关参数
case 0:
length = length - n + 1;
n_left = n_right = 0;
break;
case 1:
n_left = (npy_intp)(n/2);
n_right = n - n_left - 1;
break;
case 2:
n_right = n - 1;
n_left = n - 1;
length = length + n - 1;
break;
default:
// 如果 mode 不是 0、1 或 2,抛出异常并返回 NULL 指针
PyErr_SetString(PyExc_ValueError, "mode must be 0, 1, or 2");
return NULL;
}
/*
* 需要选择一个能容纳总和的输出数组
* -- 使用优先级确定子类型。
*/
// 根据给定的参数创建一个新的数组,用于保存和的结果
ret = new_array_for_sum(ap1, ap2, NULL, 1, &length, typenum, NULL);
if (ret == NULL) {
return NULL;
}
// 获取 ret 数组的 dot 函数
dot = PyDataType_GetArrFuncs(PyArray_DESCR(ret))->dotfunc;
if (dot == NULL) {
// 如果 dot 函数为 NULL,抛出异常并清理 ret 后返回 NULL 指针
PyErr_SetString(PyExc_ValueError,
"function not available for this data type");
goto clean_ret;
}
NPY_BEGIN_THREADS_DESCR(PyArray_DESCR(ret));
// 获取数组 ap1 和 ap2 的步长
is1 = PyArray_STRIDES(ap1)[0];
is2 = PyArray_STRIDES(ap2)[0];
// 获取输出数组的起始地址和单元大小
op = PyArray_DATA(ret);
os = PyArray_ITEMSIZE(ret);
// 获取数组 ap1 和 ap2 的数据地址
ip1 = PyArray_DATA(ap1);
ip2 = PyArray_BYTES(ap2) + n_left*is2;
n = n - n_left;
// 对左边的部分进行 dot 运算
for (i = 0; i < n_left; i++) {
dot(ip1, is1, ip2, is2, op, n, ret);
n++;
ip2 -= is2;
op += os;
}
// 如果可以使用 small_correlate 函数,则调用它计算结果
if (small_correlate(ip1, is1, n1 - n2 + 1, PyArray_TYPE(ap1),
ip2, is2, n, PyArray_TYPE(ap2),
op, os)) {
ip1 += is1 * (n1 - n2 + 1);
op += os * (n1 - n2 + 1);
}
else {
// 否则,使用 dot 函数计算结果
for (i = 0; i < (n1 - n2 + 1); i++) {
dot(ip1, is1, ip2, is2, op, n, ret);
ip1 += is1;
op += os;
}
}
这样,你的代码现在每行都有了详细的注释,解释了每个语句的作用和意图。
for (i = 0; i < n_right; i++) {
n--;
dot(ip1, is1, ip2, is2, op, n, ret);
ip1 += is1;
op += os;
}
NPY_END_THREADS_DESCR(PyArray_DESCR(ret));
if (PyErr_Occurred()) {
goto clean_ret;
}
return ret;
/*
* Clean up and return NULL on failure
*/
clean_ret:
Py_DECREF(ret);
return NULL;
}
/*
* Revert a one dimensional array in-place
*
* Return 0 on success, other value on failure
*/
static int
_pyarray_revert(PyArrayObject *ret)
{
npy_intp length = PyArray_DIM(ret, 0); // 获取数组的长度
npy_intp os = PyArray_ITEMSIZE(ret); // 获取数组元素的大小
char *op = PyArray_DATA(ret); // 获取数组的数据指针
char *sw1 = op; // 指向数组起始位置的指针
char *sw2;
if (PyArray_ISNUMBER(ret) && !PyArray_ISCOMPLEX(ret)) {
/* Optimization for unstructured dtypes */
PyArray_CopySwapNFunc *copyswapn = PyDataType_GetArrFuncs(PyArray_DESCR(ret))->copyswapn; // 获取类型特定的数据交换函数
sw2 = op + length * os - 1; // 指向数组末尾的指针
/* First reverse the whole array byte by byte... */
while(sw1 < sw2) {
const char tmp = *sw1;
*sw1++ = *sw2;
*sw2-- = tmp;
}
/* ...then swap in place every item */
copyswapn(op, os, NULL, 0, length, 1, NULL); // 在数组中交换每个元素
}
else {
char *tmp = PyArray_malloc(PyArray_ITEMSIZE(ret)); // 分配临时空间用于交换元素
if (tmp == NULL) {
PyErr_NoMemory(); // 内存分配失败
return -1; // 返回错误值
}
sw2 = op + (length - 1) * os; // 指向数组末尾的指针
while (sw1 < sw2) {
memcpy(tmp, sw1, os); // 将 sw1 处的元素拷贝到 tmp
memcpy(sw1, sw2, os); // 将 sw2 处的元素拷贝到 sw1
memcpy(sw2, tmp, os); // 将 tmp 中的元素拷贝到 sw2
sw1 += os; // 移动指针 sw1
sw2 -= os; // 移动指针 sw2
}
PyArray_free(tmp); // 释放临时空间
}
return 0; // 返回成功标志
}
/*NUMPY_API
* correlate(a1,a2,mode)
*
* This function computes the usual correlation (correlate(a1, a2) !=
* correlate(a2, a1), and conjugate the second argument for complex inputs
*/
NPY_NO_EXPORT PyObject *
PyArray_Correlate2(PyObject *op1, PyObject *op2, int mode)
{
PyArrayObject *ap1, *ap2, *ret = NULL;
int typenum;
PyArray_Descr *typec;
int inverted;
int st;
typenum = PyArray_ObjectType(op1, NPY_NOTYPE); // 获取第一个输入对象的数据类型
if (typenum == NPY_NOTYPE) {
return NULL; // 数据类型获取失败,返回 NULL
}
typenum = PyArray_ObjectType(op2, typenum); // 获取第二个输入对象的数据类型
if (typenum == NPY_NOTYPE) {
return NULL; // 数据类型获取失败,返回 NULL
}
typec = PyArray_DescrFromType(typenum); // 根据数据类型创建描述符
Py_INCREF(typec); // 增加描述符的引用计数
ap1 = (PyArrayObject *)PyArray_FromAny(op1, typec, 1, 1,
NPY_ARRAY_DEFAULT, NULL); // 将第一个输入对象转换为数组对象
if (ap1 == NULL) {
Py_DECREF(typec);
return NULL; // 转换失败,返回 NULL
}
ap2 = (PyArrayObject *)PyArray_FromAny(op2, typec, 1, 1,
NPY_ARRAY_DEFAULT, NULL); // 将第二个输入对象转换为数组对象
if (ap2 == NULL) {
goto clean_ap1; // 转换失败,跳转到清理 ap1 的标签
}
if (PyArray_ISCOMPLEX(ap2)) {
PyArrayObject *cap2;
cap2 = (PyArrayObject *)PyArray_Conjugate(ap2, NULL); // 对第二个数组对象取共轭
if (cap2 == NULL) {
goto clean_ap2; // 共轭操作失败,跳转到清理 ap2 的标签
}
Py_DECREF(ap2);
ap2 = cap2; // 将共轭后的数组对象赋给 ap2
}
ret = _pyarray_correlate(ap1, ap2, typenum, mode, &inverted); // 调用相关函数计算相关性
if (ret == NULL) {
goto clean_ap2; // 相关性计算失败,跳转到清理 ap2 的标签
}
/*
* If we inverted input orders, we need to reverse the output array (i.e.
* ret = ret[::-1])
*/
if (inverted) {
st = _pyarray_revert(ret); // 如果输入顺序反转,需要反转输出数组
if (st) {
goto clean_ret; // 反转操作失败,跳转到清理 ret 的标签
}
}
// 递减引用计数,减少对ap1指向对象的引用
Py_DECREF(ap1);
// 递减引用计数,减少对ap2指向对象的引用
Py_DECREF(ap2);
// 返回ret对象的PyObject指针类型
return (PyObject *)ret;
/* 清理变量和返回 NULL */
clean_ret:
Py_DECREF(ret);
/* 清理变量 ap2 */
clean_ap2:
Py_DECREF(ap2);
/* 清理变量 ap1 */
clean_ap1:
Py_DECREF(ap1);
return NULL;
}
/*NUMPY_API
* Numeric.correlate(a1,a2,mode)
*/
/* 导出的 NumPy API 函数,计算数组 a1 和 a2 的相关性 */
NPY_NO_EXPORT PyObject *
PyArray_Correlate(PyObject *op1, PyObject *op2, int mode)
{
PyArrayObject *ap1, *ap2, *ret = NULL;
int typenum;
int unused;
PyArray_Descr *typec;
/* 确定 op1 的类型编号 */
typenum = PyArray_ObjectType(op1, NPY_NOTYPE);
if (typenum == NPY_NOTYPE) {
return NULL;
}
/* 根据 op1 的类型编号确定 op2 的类型编号 */
typenum = PyArray_ObjectType(op2, typenum);
if (typenum == NPY_NOTYPE) {
return NULL;
}
/* 根据类型编号创建描述符对象 */
typec = PyArray_DescrFromType(typenum);
Py_INCREF(typec);
/* 将 op1 转换为 PyArrayObject 类型 */
ap1 = (PyArrayObject *)PyArray_FromAny(op1, typec, 1, 1,
NPY_ARRAY_DEFAULT, NULL);
if (ap1 == NULL) {
Py_DECREF(typec);
return NULL;
}
/* 将 op2 转换为 PyArrayObject 类型 */
ap2 = (PyArrayObject *)PyArray_FromAny(op2, typec, 1, 1,
NPY_ARRAY_DEFAULT, NULL);
if (ap2 == NULL) {
goto fail;
}
/* 调用底层的 _pyarray_correlate 函数计算相关性 */
ret = _pyarray_correlate(ap1, ap2, typenum, mode, &unused);
if (ret == NULL) {
goto fail;
}
/* 释放 ap1 和 ap2 对象的引用计数 */
Py_DECREF(ap1);
Py_DECREF(ap2);
return (PyObject *)ret;
fail:
/* 出错时释放 ap1、ap2 和 ret 对象的引用计数 */
Py_XDECREF(ap1);
Py_XDECREF(ap2);
Py_XDECREF(ret);
return NULL;
}
/* 静态函数,用于实现 NumPy 中的 array_putmask 函数 */
static PyObject *
array_putmask(PyObject *NPY_UNUSED(module), PyObject *const *args,
Py_ssize_t len_args, PyObject *kwnames )
{
PyObject *mask, *values;
PyObject *array;
NPY_PREPARE_ARGPARSER;
/* 解析参数,验证参数类型和个数 */
if (npy_parse_arguments("putmask", args, len_args, kwnames,
"", NULL, &array,
"mask", NULL, &mask,
"values", NULL, &values,
NULL, NULL, NULL) < 0) {
return NULL;
}
/* 检查 array 是否为 NumPy 数组 */
if (!PyArray_Check(array)) {
PyErr_SetString(PyExc_TypeError,
"argument a of putmask must be a numpy array");
}
/* 调用 PyArray_PutMask 函数处理数据 */
return PyArray_PutMask((PyArrayObject *)array, values, mask);
}
/*NUMPY_API
*
* 判断两个数据类型描述符是否等价(基本种类和大小相同)
*/
NPY_NO_EXPORT unsigned char
PyArray_EquivTypes(PyArray_Descr *type1, PyArray_Descr *type2)
{
/* 如果两个描述符指针相同,说明描述符相等 */
if (type1 == type2) {
return 1;
}
/*
* 使用 PyArray_GetCastInfo 而不是 PyArray_CanCastTypeTo,因为它支持
* 旧的灵活数据类型作为输入。
*/
npy_intp view_offset;
/* 获取类型转换的安全性 */
NPY_CASTING safety = PyArray_GetCastInfo(type1, type2, NULL, &view_offset);
if (safety < 0) {
PyErr_Clear();
return 0;
}
/* 如果转换安全性为 "无转换",则认为这两种类型等价 */
return PyArray_MinCastSafety(safety, NPY_NO_CASTING) == NPY_NO_CASTING;
}
/*NUMPY_API*/
NPY_NO_EXPORT unsigned char
PyArray_EquivTypenums(int typenum1, int typenum2)
{
PyArray_Descr *d1, *d2;
npy_bool ret;
/* 如果两个类型编号相同,返回成功 */
if (typenum1 == typenum2) {
return NPY_SUCCEED;
}
/* 根据类型编号创建描述符对象 */
d1 = PyArray_DescrFromType(typenum1);
d2 = PyArray_DescrFromType(typenum2);
/* 如果两个类型编号相同,返回成功 */
if (typenum1 == typenum2) {
return NPY_SUCCEED;
}
/* 根据类型编号创建描述符对象 */
d1 = PyArray_DescrFromType(typenum1);
d2 = PyArray_DescrFromType(typenum2);
ret = PyArray_EquivTypes(d1, d2);
Py_DECREF(d1);
Py_DECREF(d2);
return ret;
/*** END C-API FUNCTIONS **/
/*
* NOTE: The order specific stride setting is not necessary to preserve
* contiguity and could be removed. However, this way the resulting
* strides strides look better for fortran order inputs.
*/
static NPY_STEALS_REF_TO_ARG(1) PyObject *
_prepend_ones(PyArrayObject *arr, int nd, int ndmin, NPY_ORDER order)
{
npy_intp newdims[NPY_MAXDIMS]; // 用于存放新维度大小的数组
npy_intp newstrides[NPY_MAXDIMS]; // 用于存放新步幅大小的数组
npy_intp newstride; // 新步幅值
int i, k, num; // 循环计数器和辅助变量
PyObject *ret; // 返回的 Python 对象
PyArray_Descr *dtype; // 数组的数据类型描述符
// 根据输入的顺序和数组属性,确定新的步幅值
if (order == NPY_FORTRANORDER || PyArray_ISFORTRAN(arr) || PyArray_NDIM(arr) == 0) {
newstride = PyArray_ITEMSIZE(arr); // 对于 Fortran 顺序或者已经是 Fortran 的数组,步幅为元素大小
}
else {
newstride = PyArray_STRIDES(arr)[0] * PyArray_DIMS(arr)[0]; // 否则,步幅为首元素步幅乘以首元素大小
}
num = ndmin - nd; // 计算需要添加的新维度数量
for (i = 0; i < num; i++) {
newdims[i] = 1; // 前 num 个维度大小设为 1
newstrides[i] = newstride; // 对应的步幅设为新步幅值
}
for (i = num; i < ndmin; i++) {
k = i - num;
newdims[i] = PyArray_DIMS(arr)[k]; // 后面的维度大小保持与原数组一致
newstrides[i] = PyArray_STRIDES(arr)[k]; // 对应的步幅也保持与原数组一致
}
dtype = PyArray_DESCR(arr); // 获取原数组的数据类型描述符
Py_INCREF(dtype); // 增加数据类型描述符的引用计数
ret = PyArray_NewFromDescrAndBase(
Py_TYPE(arr), dtype,
ndmin, newdims, newstrides, PyArray_DATA(arr),
PyArray_FLAGS(arr), (PyObject *)arr, (PyObject *)arr); // 根据给定参数创建新的数组对象
Py_DECREF(arr); // 减少原数组对象的引用计数
return ret; // 返回新创建的数组对象
}
((order) == NPY_ANYORDER || \
(order) == NPY_KEEPORDER || \
((order) == NPY_CORDER && PyArray_IS_C_CONTIGUOUS(op)) || \
((order) == NPY_FORTRANORDER && PyArray_IS_F_CONTIGUOUS(op)))
static inline PyObject *
_array_fromobject_generic(
PyObject *op, PyArray_Descr *in_descr, PyArray_DTypeMeta *in_DType,
NPY_COPYMODE copy, NPY_ORDER order, npy_bool subok, int ndmin)
{
PyArrayObject *oparr = NULL, *ret = NULL; // 输入和输出的数组对象
PyArray_Descr *oldtype = NULL; // 旧的数据类型描述符
int nd, flags = 0; // 数组维度和标志位
/* Hold on to `in_descr` as `dtype`, since we may also set it below. */
Py_XINCREF(in_descr); // 增加输入的数据类型描述符的引用计数
PyArray_Descr *dtype = in_descr; // 设置数组的数据类型描述符
if (ndmin > NPY_MAXDIMS) { // 如果指定的最小维度大于最大允许维度
PyErr_Format(PyExc_ValueError,
"ndmin bigger than allowable number of dimensions "
"NPY_MAXDIMS (=%d)", NPY_MAXDIMS);
goto finish; // 报错并跳到结束标签
}
/* fast exit if simple call */
}
if (copy == NPY_COPY_ALWAYS) { // 如果指定总是复制数据
flags = NPY_ARRAY_ENSURECOPY; // 设置标志位,确保复制数据
}
else if (copy == NPY_COPY_NEVER) { // 如果指定从不复制数据
flags = NPY_ARRAY_ENSURENOCOPY; // 设置标志位,确保不复制数据
}
if (order == NPY_CORDER) { // 如果指定 C 顺序
flags |= NPY_ARRAY_C_CONTIGUOUS; // 设置标志位,确保 C 连续
}
else if ((order == NPY_FORTRANORDER)
/* order == NPY_ANYORDER && */
|| (PyArray_Check(op) &&
PyArray_ISFORTRAN((PyArrayObject *)op))) { // 如果指定 Fortran 顺序或者输入数组为 Fortran 连续
flags |= NPY_ARRAY_F_CONTIGUOUS; // 设置标志位,确保 Fortran 连续
}
if (!subok) { // 如果不允许创建子类数组
flags |= NPY_ARRAY_ENSUREARRAY; // 设置标志位,确保创建数组的副本
}
flags |= NPY_ARRAY_FORCECAST; // 强制进行类型转换
ret = (PyArrayObject *)PyArray_CheckFromAny_int(
op, dtype, in_DType, 0, 0, flags, NULL); // 检查输入对象并返回相应的数组对象
finish:
// 释放输入数据类型描述符的引用
Py_XDECREF(dtype);
return ret; // 返回最终的数组对象
}
finish:
// 释放 dtype 所指向的 Python 对象的资源
Py_XDECREF(dtype);
// 如果 ret 为 NULL,则返回 NULL
if (ret == NULL) {
return NULL;
}
// 获取 ret 的维度数
nd = PyArray_NDIM(ret);
// 如果 ret 的维度数大于等于 ndmin,则直接返回 ret
if (nd >= ndmin) {
return (PyObject *)ret;
}
/*
* 创建一个新的数组,使用相同的数据,但在形状上添加 ones
* 这里会获取 ret 的引用
*/
return _prepend_ones(ret, nd, ndmin, order);
}
static PyObject *
array_array(PyObject *NPY_UNUSED(ignored),
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
PyObject *op;
npy_bool subok = NPY_FALSE;
NPY_COPYMODE copy = NPY_COPY_ALWAYS;
int ndmin = 0;
npy_dtype_info dt_info = {NULL, NULL};
NPY_ORDER order = NPY_KEEPORDER;
PyObject *like = Py_None;
NPY_PREPARE_ARGPARSER;
// 如果参数数量不为1或者关键字参数不为空,则解析参数
if (len_args != 1 || (kwnames != NULL)) {
if (npy_parse_arguments("array", args, len_args, kwnames,
"object", NULL, &op,
"|dtype", &PyArray_DTypeOrDescrConverterOptional, &dt_info,
"$copy", &PyArray_CopyConverter, ©,
"$order", &PyArray_OrderConverter, &order,
"$subok", &PyArray_BoolConverter, &subok,
"$ndmin", &PyArray_PythonPyIntFromInt, &ndmin,
"$like", NULL, &like,
NULL, NULL, NULL) < 0) {
// 解析参数失败时释放内存并返回 NULL
Py_XDECREF(dt_info.descr);
Py_XDECREF(dt_info.dtype);
return NULL;
}
// 如果 like 不是 Py_None,则尝试创建一个新的数组函数
if (like != Py_None) {
PyObject *deferred = array_implement_c_array_function_creation(
"array", like, NULL, NULL, args, len_args, kwnames);
// 如果成功创建,则返回新的数组对象
if (deferred != Py_NotImplemented) {
Py_XDECREF(dt_info.descr);
Py_XDECREF(dt_info.dtype);
return deferred;
}
}
}
else {
// 参数数量为1且没有关键字参数时,快速路径,直接使用第一个参数作为 op
op = args[0];
}
// 调用通用的对象转换为数组函数,返回转换后的结果
PyObject *res = _array_fromobject_generic(
op, dt_info.descr, dt_info.dtype, copy, order, subok, ndmin);
// 释放描述符和数据类型信息的引用
Py_XDECREF(dt_info.descr);
Py_XDECREF(dt_info.dtype);
return res;
}
static PyObject *
array_asarray(PyObject *NPY_UNUSED(ignored),
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
PyObject *op;
NPY_COPYMODE copy = NPY_COPY_IF_NEEDED;
npy_dtype_info dt_info = {NULL, NULL};
NPY_ORDER order = NPY_KEEPORDER;
NPY_DEVICE device = NPY_DEVICE_CPU;
PyObject *like = Py_None;
NPY_PREPARE_ARGPARSER;
// 检查传入参数个数是否为1,且关键字参数列表是否为空
if (len_args != 1 || (kwnames != NULL)) {
// 尝试解析函数参数,如果失败则释放资源并返回空
if (npy_parse_arguments("asarray", args, len_args, kwnames,
"a", NULL, &op,
"|dtype", &PyArray_DTypeOrDescrConverterOptional, &dt_info,
"|order", &PyArray_OrderConverter, &order,
"$device", &PyArray_DeviceConverterOptional, &device,
"$copy", &PyArray_CopyConverter, ©,
"$like", NULL, &like,
NULL, NULL, NULL) < 0) {
Py_XDECREF(dt_info.descr);
Py_XDECREF(dt_info.dtype);
return NULL;
}
// 如果指定了 'like' 参数,则调用函数创建一个基于 'like' 的数组
if (like != Py_None) {
PyObject *deferred = array_implement_c_array_function_creation(
"asarray", like, NULL, NULL, args, len_args, kwnames);
// 如果创建成功,返回创建的数组对象
if (deferred != Py_NotImplemented) {
Py_XDECREF(dt_info.descr);
Py_XDECREF(dt_info.dtype);
return deferred;
}
}
}
else {
// 如果参数个数为1且没有关键字参数,则直接将第一个参数作为 'op'
op = args[0];
}
// 调用通用的从 Python 对象创建数组的函数
PyObject *res = _array_fromobject_generic(
op, dt_info.descr, dt_info.dtype, copy, order, NPY_FALSE, 0);
// 释放 'dt_info' 中的资源
Py_XDECREF(dt_info.descr);
Py_XDECREF(dt_info.dtype);
// 返回创建的数组对象
return res;
static PyObject *
array_asanyarray(PyObject *NPY_UNUSED(ignored),
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
// 定义操作对象
PyObject *op;
// 指定复制模式,默认为 NPY_COPY_IF_NEEDED
NPY_COPYMODE copy = NPY_COPY_IF_NEEDED;
// 定义 dtype 信息结构体,初始为 NULL
npy_dtype_info dt_info = {NULL, NULL};
// 指定数组的存储顺序,默认为 NPY_KEEPORDER
NPY_ORDER order = NPY_KEEPORDER;
// 指定设备类型,默认为 NPY_DEVICE_CPU
NPY_DEVICE device = NPY_DEVICE_CPU;
// 用于指定类似数组对象,默认为 Py_None
PyObject *like = Py_None;
// 定义参数解析器
NPY_PREPARE_ARGPARSER;
// 如果传入的参数个数不为1,或者存在关键字参数
if (len_args != 1 || (kwnames != NULL)) {
// 解析参数,可选参数有 'dtype', 'order', 'device', 'copy', 'like'
if (npy_parse_arguments("asanyarray", args, len_args, kwnames,
"a", NULL, &op,
"|dtype", &PyArray_DTypeOrDescrConverterOptional, &dt_info,
"|order", &PyArray_OrderConverter, &order,
"$device", &PyArray_DeviceConverterOptional, &device,
"$copy", &PyArray_CopyConverter, ©,
"$like", NULL, &like,
NULL, NULL, NULL) < 0) {
// 解析失败时释放 dtype 相关资源并返回 NULL
Py_XDECREF(dt_info.descr);
Py_XDECREF(dt_info.dtype);
return NULL;
}
// 如果 like 不是 Py_None,尝试创建类似数组的延迟对象
if (like != Py_None) {
PyObject *deferred = array_implement_c_array_function_creation(
"asanyarray", like, NULL, NULL, args, len_args, kwnames);
// 如果成功创建延迟对象,释放 dtype 相关资源并返回延迟对象
if (deferred != Py_NotImplemented) {
Py_XDECREF(dt_info.descr);
Py_XDECREF(dt_info.dtype);
return deferred;
}
}
}
else {
// 如果参数个数为1且没有关键字参数,直接取第一个参数作为操作对象
op = args[0];
}
// 调用通用的对象转数组函数,返回结果赋给 res
PyObject *res = _array_fromobject_generic(
op, dt_info.descr, dt_info.dtype, copy, order, NPY_TRUE, 0);
// 释放 dtype 相关资源
Py_XDECREF(dt_info.descr);
Py_XDECREF(dt_info.dtype);
// 返回转换后的数组对象
return res;
}
``````py
// 定义名为 array_ascontiguousarray 的静态函数,用于将输入对象转换为 NumPy 连续数组
static PyObject *
array_ascontiguousarray(PyObject *NPY_UNUSED(ignored),
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
// 定义操作对象
PyObject *op;
// 定义 dtype 信息结构体,初始为 NULL
npy_dtype_info dt_info = {NULL, NULL};
// 用于指定类似数组对象,默认为 Py_None
PyObject *like = Py_None;
// 定义参数解析器
NPY_PREPARE_ARGPARSER;
// 如果传入的参数个数不为1,或者存在关键字参数
if (len_args != 1 || (kwnames != NULL)) {
// 解析参数,可选参数有 'dtype', 'like'
if (npy_parse_arguments("ascontiguousarray", args, len_args, kwnames,
"a", NULL, &op,
"|dtype", &PyArray_DTypeOrDescrConverterOptional, &dt_info,
"$like", NULL, &like,
NULL, NULL, NULL) < 0) {
// 解析失败时释放 dtype 相关资源并返回 NULL
Py_XDECREF(dt_info.descr);
Py_XDECREF(dt_info.dtype);
return NULL;
}
// 如果 like 不是 Py_None,尝试创建类似数组的延迟对象
if (like != Py_None) {
PyObject *deferred = array_implement_c_array_function_creation(
"ascontiguousarray", like, NULL, NULL, args, len_args, kwnames);
// 如果成功创建延迟对象,释放 dtype 相关资源并返回延迟对象
if (deferred != Py_NotImplemented) {
Py_XDECREF(dt_info.descr);
Py_XDECREF(dt_info.dtype);
return deferred;
}
}
}
else {
// 如果参数个数为1且没有关键字参数,直接取第一个参数作为操作对象
op = args[0];
}
// 调用通用的对象转数组函数,返回结果赋给 res
PyObject *res = _array_fromobject_generic(
op, dt_info.descr, dt_info.dtype, NPY_COPY_IF_NEEDED, NPY_CORDER, NPY_FALSE,
1);
// 释放 dtype 相关资源
Py_XDECREF(dt_info.descr);
Py_XDECREF(dt_info.dtype);
// 返回转换后的连续数组对象
return res;
}
/*
PyObject 是 Python 中表示任意对象的 C 结构体指针类型
NPY_UNUSED 宏用于标记未使用的参数,通常用于编译器静默未使用参数的警告
ignored 参数命名未使用,可以在函数体内不使用它们
*/
array_asfortranarray(PyObject *NPY_UNUSED(ignored),
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
/*
op 用于存储传递给函数的第一个参数
npy_dtype_info 结构体用于存储 dtype 相关信息的结构体
like 变量用于存储传递给函数的关键字参数 "$like" 的值,默认为 Py_None
NPY_PREPARE_ARGPARSER 宏用于为参数解析做准备
*/
PyObject *op;
npy_dtype_info dt_info = {NULL, NULL};
PyObject *like = Py_None;
NPY_PREPARE_ARGPARSER;
/*
检查参数数量是否为 1 或关键字参数是否为 NULL,若不是则进行参数解析
*/
if (len_args != 1 || (kwnames != NULL)) {
/*
如果参数解析失败,则释放资源并返回 NULL
*/
if (npy_parse_arguments("asfortranarray", args, len_args, kwnames,
"a", NULL, &op,
"|dtype", &PyArray_DTypeOrDescrConverterOptional, &dt_info,
"$like", NULL, &like,
NULL, NULL, NULL) < 0) {
Py_XDECREF(dt_info.descr);
Py_XDECREF(dt_info.dtype);
return NULL;
}
/*
如果 like 不等于 Py_None,则调用 array_implement_c_array_function_creation 函数创建一个延迟对象
*/
if (like != Py_None) {
PyObject *deferred = array_implement_c_array_function_creation(
"asfortranarray", like, NULL, NULL, args, len_args, kwnames);
/*
如果创建成功,则释放资源并返回延迟对象
*/
if (deferred != Py_NotImplemented) {
Py_XDECREF(dt_info.descr);
Py_XDECREF(dt_info.dtype);
return deferred;
}
}
}
else {
/*
如果参数数量为 1 并且关键字参数为 NULL,则直接将第一个参数赋给 op
*/
op = args[0];
}
/*
调用 _array_fromobject_generic 函数创建一个新的数组对象
*/
PyObject *res = _array_fromobject_generic(
op, dt_info.descr, dt_info.dtype, NPY_COPY_IF_NEEDED, NPY_FORTRANORDER,
NPY_FALSE, 1);
Py_XDECREF(dt_info.descr);
Py_XDECREF(dt_info.dtype);
return res;
}
/*
PyObject 是 Python 中表示任意对象的 C 结构体指针类型
NPY_UNUSED 宏用于标记未使用的参数,通常用于编译器静默未使用参数的警告
ignored 参数命名未使用,可以在函数体内不使用它们
*/
static PyObject *
array_copyto(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds)
{
/*
kwlist 是一个静态的字符指针数组,用于 PyArg_ParseTupleAndKeywords 函数的关键字参数列表
wheremask_in, dst, src, wheremask 是用于存储传递给函数的参数和中间变量的 PyObject 和 PyArrayObject 类型指针
casting 是用于存储传递给函数的参数 "casting" 的值,默认为 NPY_SAME_KIND_CASTING
*/
static char *kwlist[] = {"dst", "src", "casting", "where", NULL};
PyObject *wheremask_in = NULL;
PyArrayObject *dst = NULL, *src = NULL, *wheremask = NULL;
NPY_CASTING casting = NPY_SAME_KIND_CASTING;
/*
使用 PyArg_ParseTupleAndKeywords 函数解析传递给函数的参数
*/
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O&|O&O:copyto", kwlist,
&PyArray_Type, &dst,
&PyArray_Converter, &src,
&PyArray_CastingConverter, &casting,
&wheremask_in)) {
goto fail;
}
/*
如果 wheremask_in 不为 NULL,则创建一个布尔类型的 where mask 数组
*/
if (wheremask_in != NULL) {
/* Get the boolean where mask */
PyArray_Descr *dtype = PyArray_DescrFromType(NPY_BOOL);
if (dtype == NULL) {
goto fail;
}
wheremask = (PyArrayObject *)PyArray_FromAny(wheremask_in,
dtype, 0, 0, 0, NULL);
if (wheremask == NULL) {
goto fail;
}
}
/*
调用 PyArray_AssignArray 函数执行数组赋值操作
*/
if (PyArray_AssignArray(dst, src, wheremask, casting) < 0) {
goto fail;
}
/*
释放 src 和 wheremask 资源,并返回 None 对象
*/
Py_XDECREF(src);
Py_XDECREF(wheremask);
Py_RETURN_NONE;
fail:
/*
如果发生错误,释放 src 和 wheremask 资源,并返回 NULL
*/
Py_XDECREF(src);
Py_XDECREF(wheremask);
return NULL;
}
/*
PyObject 是 Python 中表示任意对象的 C 结构体指针类型
NPY_UNUSED 宏用于标记未使用的参数,通常用于编译器静默未使用参数的警告
ignored 参数命名未使用,可以在函数体内不使用它们
*/
static PyObject *
array_empty(PyObject *NPY_UNUSED(ignored),
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
/*
dt_info 用于存储 dtype 相关信息的结构体
shape 用于存储创建数组的形状信息的结构体
order 用于存储数组存储顺序的枚举值,默认为 NPY_CORDER
is_f_order 用于判断数组是否以 Fortran 顺序存储的布尔值
ret 是返回的 PyArrayObject 类型指针
device 用于存储数组存储设备类型的枚举值,默认为 NPY_DEVICE_CPU
like 变量用于存储传递给函数的关键字参数 "$like" 的值,默认为 Py_None
NPY_PREPARE_ARGPARSER 宏用于为参数解析做准备
*/
npy_dtype_info dt_info = {NULL, NULL};
PyArray_Dims shape = {NULL, 0};
NPY_ORDER order = NPY_CORDER;
npy_bool is_f_order;
PyArrayObject *ret = NULL;
NPY_DEVICE device = NPY_DEVICE_CPU;
PyObject *like = Py_None;
NPY_PREPARE_ARGPARSER;
/*
此处需要继续添加注释,以解释接下来的代码
*/
if (npy_parse_arguments("empty", args, len_args, kwnames,
"shape", &PyArray_IntpConverter, &shape,
"|dtype", &PyArray_DTypeOrDescrConverterOptional, &dt_info,
"|order", &PyArray_OrderConverter, &order,
"$device", &PyArray_DeviceConverterOptional, &device,
"$like", NULL, &like,
NULL, NULL, NULL) < 0) {
goto fail;
}
if (like != Py_None) {
PyObject *deferred = array_implement_c_array_function_creation(
"empty", like, NULL, NULL, args, len_args, kwnames);
if (deferred != Py_NotImplemented) {
Py_XDECREF(dt_info.descr);
Py_XDECREF(dt_info.dtype);
npy_free_cache_dim_obj(shape);
return deferred;
}
}
switch (order) {
case NPY_CORDER:
is_f_order = NPY_FALSE;
break;
case NPY_FORTRANORDER:
is_f_order = NPY_TRUE;
break;
default:
PyErr_SetString(PyExc_ValueError,
"only 'C' or 'F' order is permitted");
goto fail;
}
ret = (PyArrayObject *)PyArray_Empty_int(
shape.len, shape.ptr, dt_info.descr, dt_info.dtype, is_f_order);
fail:
// 释放描述符对象的引用计数
Py_XDECREF(dt_info.descr);
// 释放数据类型对象的引用计数
Py_XDECREF(dt_info.dtype);
// 释放缓存的维度对象
npy_free_cache_dim_obj(shape);
// 返回已构造的对象
return (PyObject *)ret;
}
static PyObject *
array_empty_like(PyObject *NPY_UNUSED(ignored),
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
PyArrayObject *prototype = NULL;
npy_dtype_info dt_info = {NULL, NULL};
NPY_ORDER order = NPY_KEEPORDER;
PyArrayObject *ret = NULL;
int subok = 1;
/* -1 is a special value meaning "not specified" */
// 初始化形状参数,-1 表示未指定
PyArray_Dims shape = {NULL, -1};
NPY_DEVICE device = NPY_DEVICE_CPU;
NPY_PREPARE_ARGPARSER;
// 解析传入的参数
if (npy_parse_arguments("empty_like", args, len_args, kwnames,
"prototype", &PyArray_Converter, &prototype,
"|dtype", &PyArray_DTypeOrDescrConverterOptional, &dt_info,
"|order", &PyArray_OrderConverter, &order,
"|subok", &PyArray_PythonPyIntFromInt, &subok,
"|shape", &PyArray_OptionalIntpConverter, &shape,
"$device", &PyArray_DeviceConverterOptional, &device,
NULL, NULL, NULL) < 0) {
// 解析失败,跳转到失败处理标签
goto fail;
}
// 若描述符对象不为 NULL,则增加其引用计数
if (dt_info.descr != NULL) {
Py_INCREF(dt_info.descr);
}
// 创建一个新的数组对象,形状由 shape 指定
ret = (PyArrayObject *)PyArray_NewLikeArrayWithShape(
prototype, order, dt_info.descr, dt_info.dtype,
shape.len, shape.ptr, subok);
// 释放缓存的维度对象
npy_free_cache_dim_obj(shape);
fail:
// 释放原型对象的引用计数
Py_XDECREF(prototype);
// 释放数据类型对象的引用计数
Py_XDECREF(dt_info.dtype);
// 释放描述符对象的引用计数
Py_XDECREF(dt_info.descr);
// 返回已构造的对象
return (PyObject *)ret;
}
/*
* This function is needed for supporting Pickles of
* numpy scalar objects.
*/
static PyObject *
array_scalar(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"dtype", "obj", NULL};
PyArray_Descr *typecode;
PyObject *obj = NULL, *tmpobj = NULL;
int alloc = 0;
void *dptr;
PyObject *ret;
PyObject *base = NULL;
// 解析参数,包括数据类型和对象
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|O:scalar", kwlist,
&PyArrayDescr_Type, &typecode, &obj)) {
// 解析失败,返回 NULL 表示错误
return NULL;
}
if (PyDataType_FLAGCHK(typecode, NPY_LIST_PICKLE)) {
if (typecode->type_num == NPY_OBJECT) {
/* Deprecated 2020-11-24, NumPy 1.20 */
if (DEPRECATE(
"Unpickling a scalar with object dtype is deprecated. "
"Object scalars should never be created. If this was a "
"properly created pickle, please open a NumPy issue. In "
"a best effort this returns the original object.") < 0) {
return NULL;
}
Py_INCREF(obj);
return obj;
}
/* We store the full array to unpack it here: */
if (!PyArray_CheckExact(obj)) {
/* We pickle structured voids as arrays currently */
PyErr_SetString(PyExc_RuntimeError,
"Unpickling NPY_LIST_PICKLE (structured void) scalar "
"requires an array. The pickle file may be corrupted?");
return NULL;
}
if (!PyArray_EquivTypes(PyArray_DESCR((PyArrayObject *)obj), typecode)) {
PyErr_SetString(PyExc_RuntimeError,
"Pickled array is not compatible with requested scalar "
"dtype. The pickle file may be corrupted?");
return NULL;
}
base = obj;
dptr = PyArray_BYTES((PyArrayObject *)obj);
}
else if (PyDataType_FLAGCHK(typecode, NPY_ITEM_IS_POINTER)) {
if (obj == NULL) {
obj = Py_None;
}
dptr = &obj;
}
else {
// 如果对象为 NULL
if (obj == NULL) {
// 如果类型码的元素大小为 0,则将其设置为 1
if (typecode->elsize == 0) {
typecode->elsize = 1;
}
// 分配内存以存储指定大小的数据块
dptr = PyArray_malloc(typecode->elsize);
// 如果内存分配失败,则返回内存错误异常
if (dptr == NULL) {
return PyErr_NoMemory();
}
// 将分配的内存块清零
memset(dptr, '\0', typecode->elsize);
// 设置分配标志为真
alloc = 1;
}
else {
/* 与 Python 2 NumPy pickle 的向后兼容性 */
// 如果对象是 Unicode 字符串,则尝试将其转换为 Latin-1 编码
if (PyUnicode_Check(obj)) {
tmpobj = PyUnicode_AsLatin1String(obj);
obj = tmpobj;
// 如果转换失败,则设置更详细的错误消息并返回空值
if (tmpobj == NULL) {
PyErr_SetString(PyExc_ValueError,
"Failed to encode Numpy scalar data string to "
"latin1,\npickle.load(a, encoding='latin1') is "
"assumed if unpickling.");
return NULL;
}
}
// 如果对象不是字节对象,则设置类型错误并返回空值
if (!PyBytes_Check(obj)) {
PyErr_SetString(PyExc_TypeError,
"initializing object must be a bytes object");
Py_XDECREF(tmpobj);
return NULL;
}
// 如果字节对象大小小于类型码指定的大小,则设置值错误并返回空值
if (PyBytes_GET_SIZE(obj) < typecode->elsize) {
PyErr_SetString(PyExc_ValueError,
"initialization string is too small");
Py_XDECREF(tmpobj);
return NULL;
}
// 否则,直接使用对象中的数据指针
dptr = PyBytes_AS_STRING(obj);
}
}
// 调用 PyArray_Scalar 函数来创建一个新的标量对象
ret = PyArray_Scalar(dptr, typecode, base);
/* 释放包含零值的 dptr 内存块 */
// 如果分配标志为真,则释放 dptr 指向的内存
if (alloc) {
PyArray_free(dptr);
}
// 释放临时对象的引用
Py_XDECREF(tmpobj);
// 返回创建的标量对象或者 NULL
return ret;
static PyObject *
array_zeros(PyObject *NPY_UNUSED(ignored),
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
npy_dtype_info dt_info = {NULL, NULL}; // 定义一个包含 dtype 信息的结构体
PyArray_Dims shape = {NULL, 0}; // 定义一个数组维度结构体
NPY_ORDER order = NPY_CORDER; // 设置数组存储顺序,默认为 C 风格顺序
npy_bool is_f_order = NPY_FALSE; // 标志位,表示是否使用 Fortran 风格顺序
PyArrayObject *ret = NULL; // 定义返回的 NumPy 数组对象指针
NPY_DEVICE device = NPY_DEVICE_CPU; // 设置设备类型,默认为 CPU
PyObject *like = Py_None; // 用于指定类似对象,默认为 None
NPY_PREPARE_ARGPARSER; // 宏定义,准备参数解析器
if (npy_parse_arguments("zeros", args, len_args, kwnames,
"shape", &PyArray_IntpConverter, &shape, // 解析 shape 参数为整型数组
"|dtype", &PyArray_DTypeOrDescrConverterOptional, &dt_info, // 解析 dtype 参数,可选
"|order", &PyArray_OrderConverter, &order, // 解析 order 参数,指定存储顺序
"$device", &PyArray_DeviceConverterOptional, &device, // 解析 device 参数,可选
"$like", NULL, &like, // 解析 like 参数,可选
NULL, NULL, NULL) < 0) { // 处理参数解析错误
goto finish; // 如果解析失败,跳转到 finish 标签处
}
if (like != Py_None) { // 如果 like 参数不为空
PyObject *deferred = array_implement_c_array_function_creation(
"zeros", like, NULL, NULL, args, len_args, kwnames); // 调用函数处理类似对象
if (deferred != Py_NotImplemented) { // 如果成功处理类似对象
Py_XDECREF(dt_info.descr); // 释放 dtype 信息
Py_XDECREF(dt_info.dtype); // 释放 dtype
npy_free_cache_dim_obj(shape); // 释放 shape 对象内存
return deferred; // 返回处理结果
}
}
switch (order) { // 根据指定的存储顺序进行处理
case NPY_CORDER: // 如果是 C 风格顺序
is_f_order = NPY_FALSE; // 设置为非 Fortran 风格
break;
case NPY_FORTRANORDER: // 如果是 Fortran 风格顺序
is_f_order = NPY_TRUE; // 设置为 Fortran 风格
break;
default: // 如果不是上述两种顺序
PyErr_SetString(PyExc_ValueError,
"only 'C' or 'F' order is permitted"); // 报错,只能使用 'C' 或 'F' 顺序
goto finish; // 跳转到 finish 标签处
}
ret = (PyArrayObject *)PyArray_Zeros_int(
shape.len, shape.ptr, dt_info.descr, dt_info.dtype, (int) is_f_order); // 创建全零数组对象
finish:
npy_free_cache_dim_obj(shape); // 释放 shape 对象内存
Py_XDECREF(dt_info.descr); // 释放 dtype 信息
Py_XDECREF(dt_info.dtype); // 释放 dtype
return (PyObject *)ret; // 返回创建的数组对象
}
static PyObject *
array_count_nonzero(PyObject *NPY_UNUSED(self), PyObject *const *args, Py_ssize_t len_args)
{
PyArrayObject *array; // 定义 NumPy 数组对象指针
npy_intp count; // 定义用于存储非零元素个数的变量
NPY_PREPARE_ARGPARSER; // 宏定义,准备参数解析器
if (npy_parse_arguments("count_nonzero", args, len_args, NULL,
"", PyArray_Converter, &array, // 解析必需的数组参数
NULL, NULL, NULL) < 0) { // 处理参数解析错误
return NULL; // 返回空指针表示错误
}
count = PyArray_CountNonzero(array); // 计算数组中非零元素的个数
Py_DECREF(array); // 释放数组对象的引用计数
if (count == -1) { // 如果计数返回 -1,表示出错
return NULL; // 返回空指针表示错误
}
return PyLong_FromSsize_t(count); // 返回计数结果
}
static PyObject *
array_fromstring(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *keywds)
{
char *data; // 定义字符串数据指针
Py_ssize_t nin = -1; // 定义默认的 count 参数值
char *sep = NULL; // 定义分隔符字符串指针
Py_ssize_t s; // 定义字符串数据的长度
static char *kwlist[] = {"string", "dtype", "count", "sep", "like", NULL}; // 定义关键字列表
PyObject *like = Py_None; // 定义用于指定类似对象的变量,默认为 None
PyArray_Descr *descr = NULL; // 定义 NumPy 数据类型描述符指针
if (!PyArg_ParseTupleAndKeywords(args, keywds,
"s#|O&" NPY_SSIZE_T_PYFMT "s$O:fromstring", kwlist,
&data, &s, PyArray_DescrConverter, &descr, &nin, &sep, &like)) {
Py_XDECREF(descr); // 解析参数失败时释放描述符对象
return NULL; // 返回空指针表示错误
}
// 如果 `like` 不是 Python 的 None 对象
if (like != Py_None) {
// 调用 array_implement_c_array_function_creation 函数创建一个名为 "fromstring" 的函数对象
PyObject *deferred = array_implement_c_array_function_creation(
"fromstring", like, args, keywds, NULL, 0, NULL);
// 如果返回的结果不是 Py_NotImplemented,说明函数创建成功
if (deferred != Py_NotImplemented) {
// 释放之前可能存在的描述符对象
Py_XDECREF(descr);
// 返回创建的函数对象
return deferred;
}
}
/* 二进制模式,条件复制自 PyArray_FromString */
// 如果分隔符 `sep` 为 NULL 或长度为 0
if (sep == NULL || strlen(sep) == 0) {
/* Numpy 1.14, 2017-10-19 */
// 发出警告信息表明二进制模式的 `fromstring` 方法已经被弃用,并建议使用 `frombuffer` 替代
if (DEPRECATE(
"The binary mode of fromstring is deprecated, as it behaves "
"surprisingly on unicode inputs. Use frombuffer instead") < 0) {
// 释放之前可能存在的描述符对象
Py_XDECREF(descr);
// 返回 NULL 表示出错
return NULL;
}
}
// 调用 PyArray_FromString 函数,将 `data` 转换为数组对象
return PyArray_FromString(data, (npy_intp)s, descr, (npy_intp)nin, sep);
static PyObject *
array_fromfile(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *keywds)
{
// 定义变量
PyObject *file = NULL, *ret = NULL;
PyObject *err_type = NULL, *err_value = NULL, *err_traceback = NULL;
char *sep = "";
Py_ssize_t nin = -1;
static char *kwlist[] = {"file", "dtype", "count", "sep", "offset", "like", NULL};
PyObject *like = Py_None;
PyArray_Descr *type = NULL;
int own;
npy_off_t orig_pos = 0, offset = 0;
FILE *fp;
// 解析参数
if (!PyArg_ParseTupleAndKeywords(args, keywds,
"O|O&" NPY_SSIZE_T_PYFMT "s" NPY_OFF_T_PYFMT "$O:fromfile", kwlist,
&file, PyArray_DescrConverter, &type, &nin, &sep, &offset, &like)) {
Py_XDECREF(type);
return NULL;
}
// 如果有类似对象,则尝试创建类似对象的文件
if (like != Py_None) {
PyObject *deferred = array_implement_c_array_function_creation(
"fromfile", like, args, keywds, NULL, 0, NULL);
if (deferred != Py_NotImplemented) {
Py_XDECREF(type);
return deferred;
}
}
// 将路径类对象转换为文件系统路径
file = NpyPath_PathlikeToFspath(file);
if (file == NULL) {
Py_XDECREF(type);
return NULL;
}
// 检查是否指定了偏移量但同时指定了分隔符,只有在处理二进制文件时允许偏移量参数
if (offset != 0 && strcmp(sep, "") != 0) {
PyErr_SetString(PyExc_TypeError, "'offset' argument only permitted for binary files");
Py_XDECREF(type);
Py_DECREF(file);
return NULL;
}
// 如果 file 是字节对象或 Unicode 对象,则尝试打开为二进制文件
if (PyBytes_Check(file) || PyUnicode_Check(file)) {
Py_SETREF(file, npy_PyFile_OpenFile(file, "rb"));
if (file == NULL) {
Py_XDECREF(type);
return NULL;
}
own = 1;
}
else {
own = 0;
}
// 复制文件描述符,以便于在可能的异常情况下恢复文件位置
fp = npy_PyFile_Dup2(file, "rb", &orig_pos);
if (fp == NULL) {
Py_DECREF(file);
Py_XDECREF(type);
return NULL;
}
// 若设置了偏移量,则移动文件指针到指定位置
if (npy_fseek(fp, offset, SEEK_CUR) != 0) {
PyErr_SetFromErrno(PyExc_OSError);
goto cleanup;
}
// 如果未指定数据类型,则使用默认数据类型创建描述符
if (type == NULL) {
type = PyArray_DescrFromType(NPY_DEFAULT_TYPE);
}
// 从文件中读取数据并创建 NumPy 数组
ret = PyArray_FromFile(fp, type, (npy_intp) nin, sep);
/* 如果在调用 PyArray_FromFile 时抛出异常,
* 我们需要清除异常,并稍后恢复以确保可以正确清理复制的文件描述符。
*/
cleanup:
PyErr_Fetch(&err_type, &err_value, &err_traceback);
// 关闭文件和恢复异常状态
if (npy_PyFile_DupClose2(file, fp, orig_pos) < 0) {
npy_PyErr_ChainExceptions(err_type, err_value, err_traceback);
goto fail;
}
if (own && npy_PyFile_CloseFile(file) < 0) {
npy_PyErr_ChainExceptions(err_type, err_value, err_traceback);
goto fail;
}
PyErr_Restore(err_type, err_value, err_traceback);
// 释放资源并返回结果
Py_DECREF(file);
return ret;
fail:
// 处理失败情况
Py_DECREF(file);
Py_XDECREF(ret);
return NULL;
}
PyObject *like = Py_None;
PyArray_Descr *descr = NULL;
if (!PyArg_ParseTupleAndKeywords(args, keywds,
"OO&|" NPY_SSIZE_T_PYFMT "$O:fromiter", kwlist,
&iter, PyArray_DescrConverter, &descr, &nin, &like)) {
// 如果解析参数失败,释放 descr,并返回空指针
Py_XDECREF(descr);
return NULL;
}
if (like != Py_None) {
PyObject *deferred = array_implement_c_array_function_creation(
"fromiter", like, args, keywds, NULL, 0, NULL);
if (deferred != Py_NotImplemented) {
Py_XDECREF(descr);
return deferred;
}
}
return PyArray_FromIter(iter, descr, (npy_intp)nin);
static PyObject *
array_outerproduct(PyObject *NPY_UNUSED(dummy), PyObject *const *args, Py_ssize_t len_args)
{
PyObject *b0, *a0;
NPY_PREPARE_ARGPARSER; // 准备解析函数参数
if (npy_parse_arguments("outerproduct", args, len_args, NULL,
"", NULL, &a0, // 解析第一个参数
"", NULL, &b0, // 解析第二个参数
NULL, NULL, NULL) < 0) { // 如果解析失败,返回空指针
return NULL;
}
return PyArray_Return((PyArrayObject *)PyArray_OuterProduct(a0, b0)); // 返回外积计算结果
}
/*
* 计算两个数组的矩阵乘积。
* 包括参数解析和异常处理。
*/
static PyObject *
array_matrixproduct(PyObject *NPY_UNUSED(dummy),
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
PyObject *v, *a, *o = NULL;
PyArrayObject *ret;
NPY_PREPARE_ARGPARSER; // 准备参数解析器
if (npy_parse_arguments("dot", args, len_args, kwnames,
"a", NULL, &a, // 解析参数 'a'
"b", NULL, &v, // 解析参数 'b'
"|out", NULL, &o, // 解析可选参数 'out'
NULL, NULL, NULL) < 0) {
return NULL;
}
if (o != NULL) {
if (o == Py_None) {
o = NULL;
}
else if (!PyArray_Check(o)) {
PyErr_SetString(PyExc_TypeError, "'out' must be an array");
return NULL;
}
}
// 调用底层函数计算矩阵乘积并返回结果
ret = (PyArrayObject *)PyArray_MatrixProduct2(a, v, (PyArrayObject *)o);
return PyArray_Return(ret);
}
/*
* 计算向量的共轭点积,使用BLAS进行计算。
* 对op1和op2进行扁平化处理后进行点积计算。
*/
static PyObject *
array_vdot(PyObject *NPY_UNUSED(dummy), PyObject *const *args, Py_ssize_t len_args)
{
int typenum;
char *ip1, *ip2, *op;
npy_intp n, stride1, stride2;
PyObject *op1, *op2;
npy_intp newdimptr[1] = {-1};
PyArray_Dims newdims = {newdimptr, 1};
PyArrayObject *ap1 = NULL, *ap2 = NULL, *ret = NULL;
PyArray_Descr *type;
PyArray_DotFunc *vdot;
NPY_BEGIN_THREADS_DEF;
NPY_PREPARE_ARGPARSER; // 准备参数解析器
if (npy_parse_arguments("vdot", args, len_args, NULL,
"", NULL, &op1, // 解析参数
"", NULL, &op2, // 解析参数
NULL, NULL, NULL) < 0) {
return NULL;
}
typenum = PyArray_ObjectType(op1, NPY_NOTYPE); // 获取op1的数组类型
if (typenum == NPY_NOTYPE) {
return NULL;
}
typenum = PyArray_ObjectType(op2, typenum); // 根据op1的类型获取op2的类型
if (typenum == NPY_NOTYPE) {
return NULL;
}
type = PyArray_DescrFromType(typenum); // 根据类型编号获取描述符
Py_INCREF(type);
ap1 = (PyArrayObject *)PyArray_FromAny(op1, type, 0, 0, 0, NULL); // 将op1转换为数组
if (ap1 == NULL) {
Py_DECREF(type);
goto fail;
}
op1 = PyArray_Newshape(ap1, &newdims, NPY_CORDER); // 对op1进行新维度的重塑
if (op1 == NULL) {
Py_DECREF(type);
goto fail;
}
Py_DECREF(ap1);
ap1 = (PyArrayObject *)op1;
ap2 = (PyArrayObject *)PyArray_FromAny(op2, type, 0, 0, 0, NULL); // 将op2转换为数组
if (ap2 == NULL) {
goto fail;
}
op2 = PyArray_Newshape(ap2, &newdims, NPY_CORDER); // 对op2进行新维度的重塑
if (op2 == NULL) {
goto fail;
}
Py_DECREF(ap2);
ap2 = (PyArrayObject *)op2;
if (PyArray_DIM(ap2, 0) != PyArray_DIM(ap1, 0)) { // 检查向量长度是否一致
PyErr_SetString(PyExc_ValueError,
"vectors have different lengths");
goto fail;
}
// 创建输出数组用于存储结果
ret = new_array_for_sum(ap1, ap2, NULL, 0, (npy_intp *)NULL, typenum, NULL);
if (ret == NULL) {
goto fail;
}
n = PyArray_DIM(ap1, 0); // 获取向量长度
stride1 = PyArray_STRIDE(ap1, 0); // 获取ap1的步长
stride2 = PyArray_STRIDE(ap2, 0); // 获取ap2的步长
ip1 = PyArray_DATA(ap1); // 获取ap1的数据指针
ip2 = PyArray_DATA(ap2); // 获取ap2的数据指针
op = PyArray_DATA(ret); // 获取输出数据的指针
switch (typenum) {
case NPY_CFLOAT:
vdot = (PyArray_DotFunc *)CFLOAT_vdot;
break;
case NPY_CDOUBLE:
vdot = (PyArray_DotFunc *)CDOUBLE_vdot;
break;
case NPY_CLONGDOUBLE:
vdot = (PyArray_DotFunc *)CLONGDOUBLE_vdot;
break;
case NPY_OBJECT:
vdot = (PyArray_DotFunc *)OBJECT_vdot;
break;
default:
vdot = PyDataType_GetArrFuncs(type)->dotfunc;
if (vdot == NULL) {
PyErr_SetString(PyExc_ValueError,
"function not available for this data type");
goto fail;
}
}
if (n < 500) {
vdot(ip1, stride1, ip2, stride2, op, n, NULL);
}
else {
NPY_BEGIN_THREADS_DESCR(type);
vdot(ip1, stride1, ip2, stride2, op, n, NULL);
NPY_END_THREADS_DESCR(type);
}
Py_XDECREF(ap1);
Py_XDECREF(ap2);
return PyArray_Return(ret);
/*
* Decrements the reference count of three Python objects and returns NULL.
* This is typically used when an error occurs in the function.
*/
Py_XDECREF(ap1);
Py_XDECREF(ap2);
Py_XDECREF(ret);
return NULL;
}
/*
* Parses the arguments for einsum operation from a Python tuple,
* extracts the subscripts string and operands.
*
* Returns:
* - Number of operands on success
* - -1 on error, with appropriate Python exceptions set
*/
static int
einsum_sub_op_from_str(PyObject *args, PyObject **str_obj, char **subscripts,
PyArrayObject **op)
{
int i, nop;
PyObject *subscripts_str;
nop = PyTuple_GET_SIZE(args) - 1;
if (nop <= 0) {
PyErr_SetString(PyExc_ValueError,
"must specify the einstein sum subscripts string "
"and at least one operand");
return -1;
}
else if (nop >= NPY_MAXARGS) {
PyErr_SetString(PyExc_ValueError, "too many operands");
return -1;
}
/* Get the subscripts string */
subscripts_str = PyTuple_GET_ITEM(args, 0);
if (PyUnicode_Check(subscripts_str)) {
*str_obj = PyUnicode_AsASCIIString(subscripts_str);
if (*str_obj == NULL) {
return -1;
}
subscripts_str = *str_obj;
}
*subscripts = PyBytes_AsString(subscripts_str);
if (*subscripts == NULL) {
Py_XDECREF(*str_obj);
*str_obj = NULL;
return -1;
}
/* Set the operands to NULL */
for (i = 0; i < nop; ++i) {
op[i] = NULL;
}
/* Get the operands */
for (i = 0; i < nop; ++i) {
PyObject *obj = PyTuple_GET_ITEM(args, i+1);
op[i] = (PyArrayObject *)PyArray_FROM_OF(obj, NPY_ARRAY_ENSUREARRAY);
if (op[i] == NULL) {
goto fail;
}
}
return nop;
fail:
for (i = 0; i < nop; ++i) {
Py_XDECREF(op[i]);
op[i] = NULL;
}
return -1;
}
/*
* Converts a Python sequence of subscripts into a C string.
*
* Returns:
* -1 on error (Python exception set),
* - Number of characters placed in `subscripts` on success.
*/
static int
einsum_list_to_subscripts(PyObject *obj, char *subscripts, int subsize)
{
int ellipsis = 0, subindex = 0;
npy_intp i, size;
PyObject *item;
obj = PySequence_Fast(obj, "the subscripts for each operand must "
"be a list or a tuple");
if (obj == NULL) {
return -1;
}
size = PySequence_Size(obj);
for (i = 0; i < size; ++i) {
item = PySequence_Fast_GET_ITEM(obj, i);
/* Ellipsis */
if (item == Py_Ellipsis) {
if (ellipsis) {
PyErr_SetString(PyExc_ValueError,
"each subscripts list may have only one ellipsis");
Py_DECREF(obj);
return -1;
}
if (subindex + 3 >= subsize) {
PyErr_SetString(PyExc_ValueError,
"subscripts list is too long");
Py_DECREF(obj);
return -1;
}
subscripts[subindex++] = '.';
subscripts[subindex++] = '.';
subscripts[subindex++] = '.';
ellipsis = 1;
}
/* Subscript */
else {
npy_intp s = PyArray_PyIntAsIntp(item);
/* Invalid */
if (error_converting(s)) {
PyErr_SetString(PyExc_TypeError,
"each subscript must be either an integer "
"or an ellipsis");
Py_DECREF(obj);
return -1;
}
if (subindex + 1 >= subsize) {
PyErr_SetString(PyExc_ValueError,
"subscripts list is too long");
Py_DECREF(obj);
return -1;
}
npy_bool bad_input = 0;
if (s < 0) {
bad_input = 1;
}
else if (s < 26) {
subscripts[subindex++] = 'A' + (char)s;
}
else if (s < 2*26) {
subscripts[subindex++] = 'a' + (char)s - 26;
}
else {
bad_input = 1;
}
if (bad_input) {
PyErr_SetString(PyExc_ValueError,
"subscript is not within the valid range [0, 52)");
Py_DECREF(obj);
return -1;
}
}
}
Py_DECREF(obj);
return subindex;
/*
* Fills in the subscripts, with maximum size subsize, and op,
* with the values in the tuple 'args'.
*
* Returns -1 on error, number of operands placed in op otherwise.
*/
static int
einsum_sub_op_from_lists(PyObject *args,
char *subscripts, int subsize, PyArrayObject **op)
{
int subindex = 0;
npy_intp i, nop;
// Calculate the number of operands (nop) from the size of the input tuple 'args'
nop = PyTuple_Size(args) / 2;
// Check if there are at least two elements in 'args'; otherwise, raise an error
if (nop == 0) {
PyErr_SetString(PyExc_ValueError, "must provide at least an "
"operand and a subscripts list to einsum");
return -1;
}
// Check if the number of operands exceeds the maximum allowed (NPY_MAXARGS)
else if (nop >= NPY_MAXARGS) {
PyErr_SetString(PyExc_ValueError, "too many operands");
return -1;
}
// Set all operands in the array 'op' to NULL initially
for (i = 0; i < nop; ++i) {
op[i] = NULL;
}
// Iterate through each operand in 'args' and build the subscript string
for (i = 0; i < nop; ++i) {
PyObject *obj = PyTuple_GET_ITEM(args, 2*i);
int n;
// Insert a comma between subscripts of each operand (except the first one)
if (i != 0) {
subscripts[subindex++] = ',';
if (subindex >= subsize) {
PyErr_SetString(PyExc_ValueError,
"subscripts list is too long");
goto fail;
}
}
// Convert the operand to a PyArrayObject, ensuring it's an array
op[i] = (PyArrayObject *) PyArray_FROM_OF(obj, NPY_ARRAY_ENSUREARRAY);
if (op[i] == NULL) {
goto fail;
}
// Get the subscript list for the current operand and append it to 'subscripts'
obj = PyTuple_GET_ITEM(args, 2*i+1);
n = einsum_list_to_subscripts(obj, subscripts + subindex,
subsize - subindex);
if (n < 0) {
goto fail;
}
subindex += n;
}
// If provided, add the '->' specifier to the subscript string
if (PyTuple_Size(args) == 2*nop + 1) {
PyObject *obj;
int n;
// Ensure there's enough space in 'subscripts' for '->'
if (subindex + 2 >= subsize) {
PyErr_SetString(PyExc_ValueError,
"subscripts list is too long");
goto fail;
}
subscripts[subindex++] = '-';
subscripts[subindex++] = '>';
// Append the output subscript list to 'subscripts'
obj = PyTuple_GET_ITEM(args, 2*nop);
n = einsum_list_to_subscripts(obj, subscripts + subindex,
subsize - subindex);
if (n < 0) {
goto fail;
}
subindex += n;
}
// Null-terminate the 'subscripts' string
subscripts[subindex] = '\0';
return nop;
fail:
// Clean up on failure: release all allocated operands
for (i = 0; i < nop; ++i) {
Py_XDECREF(op[i]);
op[i] = NULL;
}
return -1;
}
// 检查参数元组的大小,确保至少包含一个子集合字符串和至少一个操作数,或者至少一个操作数和其对应的子集合列表
if (PyTuple_GET_SIZE(args) < 1) {
// 抛出值错误异常,说明必须指定爱因斯坦求和子集合字符串和至少一个操作数,或者至少一个操作数和其对应的子集合列表
PyErr_SetString(PyExc_ValueError,
"must specify the einstein sum subscripts string "
"and at least one operand, or at least one operand "
"and its corresponding subscripts list");
return NULL;
}
// 获取参数元组中的第一个参数
arg0 = PyTuple_GET_ITEM(args, 0);
/* einsum('i,j', a, b), einsum('i,j->ij', a, b) */
// 如果第一个参数是字节字符串或者Unicode字符串,则根据字符串解析爱因斯坦求和的子集合和操作
if (PyBytes_Check(arg0) || PyUnicode_Check(arg0)) {
nop = einsum_sub_op_from_str(args, &str_obj, &subscripts, op);
}
/* einsum(a, [0], b, [1]), einsum(a, [0], b, [1], [0,1]) */
else {
// 否则,根据参数列表和子集合列表解析爱因斯坦求和的子集合和操作
nop = einsum_sub_op_from_lists(args, subscripts_buffer,
sizeof(subscripts_buffer), op);
subscripts = subscripts_buffer;
}
// 如果没有有效的操作数,则跳转到结束位置
if (nop <= 0) {
goto finish;
}
/* Get the keyword arguments */
// 获取关键字参数
if (kwds != NULL) {
PyObject *key, *value;
Py_ssize_t pos = 0;
// 遍历关键字字典
while (PyDict_Next(kwds, &pos, &key, &value)) {
char *str = NULL;
// 释放之前的字符串键对象,并尝试将键转换为ASCII字符串
Py_XDECREF(str_key_obj);
str_key_obj = PyUnicode_AsASCIIString(key);
// 如果成功转换,则将key更新为ASCII字符串对象
if (str_key_obj != NULL) {
key = str_key_obj;
}
// 获取键的C风格字符串表示
str = PyBytes_AsString(key);
// 如果字符串为空,清除错误并设置类型错误异常,然后跳转到结束位置
if (str == NULL) {
PyErr_Clear();
PyErr_SetString(PyExc_TypeError, "invalid keyword");
goto finish;
}
// 根据关键字字符串的值进行不同的处理
if (strcmp(str,"out") == 0) {
// 如果关键字是"out",则检查值是否为数组,是则赋给out
if (PyArray_Check(value)) {
out = (PyArrayObject *)value;
}
else {
// 否则设置类型错误异常,要求"out"参数必须是一个数组
PyErr_SetString(PyExc_TypeError,
"keyword parameter out must be an "
"array for einsum");
goto finish;
}
}
else if (strcmp(str,"order") == 0) {
// 如果关键字是"order",则转换其值为数组排序方式
if (!PyArray_OrderConverter(value, &order)) {
goto finish;
}
}
else if (strcmp(str,"casting") == 0) {
// 如果关键字是"casting",则转换其值为数组类型转换方式
if (!PyArray_CastingConverter(value, &casting)) {
goto finish;
}
}
else if (strcmp(str,"dtype") == 0) {
// 如果关键字是"dtype",则转换其值为数组数据类型描述符
if (!PyArray_DescrConverter2(value, &dtype)) {
goto finish;
}
}
else {
// 否则设置类型错误异常,说明关键字不是有效的einsum关键字
PyErr_Format(PyExc_TypeError,
"'%s' is an invalid keyword for einsum",
str);
goto finish;
}
}
}
// 执行爱因斯坦求和操作,返回结果对象
ret = (PyObject *)PyArray_EinsteinSum(subscripts, nop, op, dtype,
order, casting, out);
// 如果返回结果不为空且没有提供输出数组,则尝试将结果转换为标量
if (ret != NULL && out == NULL) {
ret = PyArray_Return((PyArrayObject *)ret);
}
finish:
for (i = 0; i < nop; ++i) {
// 释放 Python 对象数组中第 i 个对象的引用计数
Py_XDECREF(op[i]);
}
// 释放 dtype 对象的引用计数
Py_XDECREF(dtype);
// 释放 str_obj 对象的引用计数
Py_XDECREF(str_obj);
// 释放 str_key_obj 对象的引用计数
Py_XDECREF(str_key_obj);
/* out is a borrowed reference */
// 返回函数结果
return ret;
}
static PyObject *
array_correlate(PyObject *NPY_UNUSED(dummy),
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
PyObject *shape, *a0;
int mode = 0;
NPY_PREPARE_ARGPARSER;
if (npy_parse_arguments("correlate", args, len_args, kwnames,
// 解析函数参数,获取数组 a0 和 shape
"a", NULL, &a0,
"v", NULL, &shape,
// 可选参数 mode,指定相关运算的模式
"|mode", &PyArray_CorrelatemodeConverter, &mode,
NULL, NULL, NULL) < 0) {
// 参数解析失败,返回 NULL
return NULL;
}
// 调用 PyArray_Correlate 函数进行相关运算,并返回其结果
return PyArray_Correlate(a0, shape, mode);
}
static PyObject*
array_correlate2(PyObject *NPY_UNUSED(dummy),
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
PyObject *shape, *a0;
int mode = 0;
NPY_PREPARE_ARGPARSER;
if (npy_parse_arguments("correlate2", args, len_args, kwnames,
// 解析函数参数,获取数组 a0 和 shape
"a", NULL, &a0,
"v", NULL, &shape,
// 可选参数 mode,指定相关运算的模式
"|mode", &PyArray_CorrelatemodeConverter, &mode,
NULL, NULL, NULL) < 0) {
// 参数解析失败,返回 NULL
return NULL;
}
// 调用 PyArray_Correlate2 函数进行相关运算,并返回其结果
return PyArray_Correlate2(a0, shape, mode);
}
static PyObject *
array_arange(PyObject *NPY_UNUSED(ignored),
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
PyObject *o_start = NULL, *o_stop = NULL, *o_step = NULL, *range=NULL;
PyArray_Descr *typecode = NULL;
NPY_DEVICE device = NPY_DEVICE_CPU;
PyObject *like = Py_None;
NPY_PREPARE_ARGPARSER;
if (npy_parse_arguments("arange", args, len_args, kwnames,
// 解析函数参数,可选参数 start, stop, step, dtype, device, like
"|start", NULL, &o_start,
"|stop", NULL, &o_stop,
"|step", NULL, &o_step,
"|dtype", &PyArray_DescrConverter2, &typecode,
"$device", &PyArray_DeviceConverterOptional, &device,
"$like", NULL, &like,
NULL, NULL, NULL) < 0) {
// 参数解析失败,释放 typecode 对象的引用计数并返回 NULL
Py_XDECREF(typecode);
return NULL;
}
// 如果指定了 like 参数,尝试使用数组函数创建函数
if (like != Py_None) {
PyObject *deferred = array_implement_c_array_function_creation(
"arange", like, NULL, NULL, args, len_args, kwnames);
// 如果成功创建,返回创建结果
if (deferred != Py_NotImplemented) {
Py_XDECREF(typecode);
return deferred;
}
}
// 如果没有指定 stop 参数且没有其他位置参数,抛出类型错误
if (o_stop == NULL) {
if (len_args == 0){
PyErr_SetString(PyExc_TypeError,
"arange() requires stop to be specified.");
Py_XDECREF(typecode);
return NULL;
}
}
else if (o_start == NULL) {
// 如果没有指定 start 参数但指定了 stop 参数,则调整参数位置
o_start = o_stop;
o_stop = NULL;
}
// 调用 PyArray_ArangeObj 函数生成 range 对象
range = PyArray_ArangeObj(o_start, o_stop, o_step, typecode);
Py_XDECREF(typecode);
// 返回生成的 range 对象
return range;
}
/*NUMPY_API
*
* Included at the very first so not auto-grabbed and thus not labeled.
*/
NPY_NO_EXPORT unsigned int
PyArray_GetNDArrayCVersion(void)
{
// 返回当前 NumPy 库的 ABI 版本号
return (unsigned int)NPY_ABI_VERSION;
}
/*NUMPY_API
* Returns the built-in (at compilation time) C API version
*/
NPY_NO_EXPORT unsigned int
PyArray_GetNDArrayCFeatureVersion(void)
{
// 返回编译时内置的 NumPy C API 版本号
return (unsigned int)NPY_API_VERSION;
}
static PyObject *
array__get_ndarray_c_version(
PyObject *NPY_UNUSED(dummy), PyObject *NPY_UNUSED(arg))
{
// 返回 NumPy ndarray C 版本的 Python 封装函数
return PyLong_FromLong( (long) PyArray_GetNDArrayCVersion() );
}
/*NUMPY_API
*/
NPY_NO_EXPORT int
PyArray_GetEndianness(void)
{
const union {
npy_uint32 i;
char c[4];
} bint = {0x01020304};
// 检测当前平台的字节序,并返回对应的常量
if (bint.c[0] == 1) {
return NPY_CPU_BIG; // 大端字节序
}
else if (bint.c[0] == 4) {
return NPY_CPU_LITTLE; // 小端字节序
}
else {
return NPY_CPU_UNKNOWN_ENDIAN; // 未知字节序
}
}
static PyObject *
array__reconstruct(PyObject *NPY_UNUSED(dummy), PyObject *args)
{
PyObject *ret;
PyTypeObject *subtype;
PyArray_Dims shape = {NULL, 0};
PyArray_Descr *dtype = NULL;
evil_global_disable_warn_O4O8_flag = 1;
// 解析参数,重建 ndarray 对象
if (!PyArg_ParseTuple(args, "O!O&O&:_reconstruct",
&PyType_Type, &subtype,
PyArray_IntpConverter, &shape,
PyArray_DescrConverter, &dtype)) {
goto fail;
}
// 检查 subtype 是否为 ndarray 的子类型
if (!PyType_IsSubtype(subtype, &PyArray_Type)) {
PyErr_SetString(PyExc_TypeError,
"_reconstruct: First argument must be a sub-type of ndarray");
goto fail;
}
// 根据给定的 shape 和 dtype 创建新的 ndarray 对象
ret = PyArray_NewFromDescr(subtype, dtype,
(int)shape.len, shape.ptr, NULL, NULL, 0, NULL);
npy_free_cache_dim_obj(shape);
evil_global_disable_warn_O4O8_flag = 0;
return ret;
fail:
evil_global_disable_warn_O4O8_flag = 0;
Py_XDECREF(dtype);
npy_free_cache_dim_obj(shape);
return NULL;
}
static PyObject *
array_set_datetimeparse_function(PyObject *NPY_UNUSED(self),
PyObject *NPY_UNUSED(args), PyObject *NPY_UNUSED(kwds))
{
// 设置 datetime 解析函数,但已被移除,因此直接抛出 RuntimeError
PyErr_SetString(PyExc_RuntimeError, "This function has been removed");
return NULL;
}
/*
* inner loop with constant size memcpy arguments
* this allows the compiler to replace function calls while still handling the
* alignment requirements of the platform.
*/
do { \
npy_intp i; \
for (i = 0; i < n; i++) { \
if (*csrc) { \
memcpy(dst, xsrc, size); \
} \
else { \
memcpy(dst, ysrc, size); \
} \
dst += size; \
xsrc += xstride; \
ysrc += ystride; \
csrc += cstride; \
} \
} while(0)
/*NUMPY_API
* Where
*/
NPY_NO_EXPORT PyObject *
PyArray_Where(PyObject *condition, PyObject *x, PyObject *y)
{
PyArrayObject *arr = NULL, *ax = NULL, *ay = NULL;
PyObject *ret = NULL;
PyArray_Descr *common_dt = NULL;
// 将 condition 转换为 PyArrayObject
arr = (PyArrayObject *)PyArray_FROM_O(condition);
if (arr == NULL) {
return NULL;
}
// 如果 x 和 y 都为 NULL,则返回 condition 的非零元素索引
if ((x == NULL) && (y == NULL)) {
ret = PyArray_Nonzero(arr);
Py_DECREF(arr);
return ret;
}
// 检查 x 和 y 是否都为空,如果是,则释放 arr 对象,设置错误信息并返回空指针
if ((x == NULL) || (y == NULL)) {
Py_DECREF(arr);
PyErr_SetString(PyExc_ValueError,
"either both or neither of x and y should be given");
return NULL;
}
// 定义 x 和 y 的类型信息结构体,初始设置函数指针为 NULL
NPY_cast_info x_cast_info = {.func = NULL};
NPY_cast_info y_cast_info = {.func = NULL};
// 将 x 转换为 PyArrayObject 类型,如果失败则跳转到错误处理标签 fail
ax = (PyArrayObject*)PyArray_FROM_O(x);
if (ax == NULL) {
goto fail;
}
// 将 y 转换为 PyArrayObject 类型,如果失败则跳转到错误处理标签 fail
ay = (PyArrayObject*)PyArray_FROM_O(y);
if (ay == NULL) {
goto fail;
}
// 标记 x 和 y 如果是 Python 标量,则标记为临时数组
npy_mark_tmp_array_if_pyscalar(x, ax, NULL);
npy_mark_tmp_array_if_pyscalar(y, ay, NULL);
// 定义迭代器的 flags
npy_uint32 flags = NPY_ITER_EXTERNAL_LOOP | NPY_ITER_BUFFERED |
NPY_ITER_REFS_OK | NPY_ITER_ZEROSIZE_OK;
// 定义操作输入对象数组
PyArrayObject * op_in[4] = {
NULL, arr, ax, ay
};
// 定义操作输入对象的 flags 数组
npy_uint32 op_flags[4] = {
NPY_ITER_WRITEONLY | NPY_ITER_ALLOCATE | NPY_ITER_NO_SUBTYPE,
NPY_ITER_READONLY,
NPY_ITER_READONLY | NPY_ITER_ALIGNED,
NPY_ITER_READONLY | NPY_ITER_ALIGNED
};
// 获取 x 和 y 的共同数据类型
common_dt = PyArray_ResultType(2, &op_in[2], 0, NULL);
if (common_dt == NULL) {
goto fail;
}
// 获取共同数据类型的元素大小
npy_intp itemsize = common_dt->elsize;
// 如果 x 和 y 没有引用,且元素大小适中,则使用简单的循环进行快速复制
// 否则,在循环中逐项处理类型转换
PyArray_Descr *x_dt, *y_dt;
int trivial_copy_loop = !PyDataType_REFCHK(common_dt) &&
((itemsize == 16) || (itemsize == 8) || (itemsize == 4) ||
(itemsize == 2) || (itemsize == 1));
if (trivial_copy_loop) {
x_dt = common_dt;
y_dt = common_dt;
}
else {
x_dt = PyArray_DESCR(op_in[2]);
y_dt = PyArray_DESCR(op_in[3]);
}
/* `PyArray_DescrFromType` cannot fail for simple builtin types: */
// 定义操作的数据类型数组
PyArray_Descr * op_dt[4] = {common_dt, PyArray_DescrFromType(NPY_BOOL), x_dt, y_dt};
// 定义迭代器对象和线程管理相关的变量
NpyIter * iter;
NPY_BEGIN_THREADS_DEF;
// 创建多输入迭代器对象
iter = NpyIter_MultiNew(
4, op_in, flags, NPY_KEEPORDER, NPY_UNSAFE_CASTING,
op_flags, op_dt);
// 释放多余的 bool 类型的数据描述符对象
Py_DECREF(op_dt[1]);
if (iter == NULL) {
goto fail;
}
/* Get the result from the iterator object array */
// 从迭代器对象数组中获取结果对象
ret = (PyObject*)NpyIter_GetOperandArray(iter)[0];
// 获取结果对象的数据描述符
PyArray_Descr *ret_dt = PyArray_DESCR((PyArrayObject *)ret);
// 定义数据传输的标志
NPY_ARRAYMETHOD_FLAGS transfer_flags = 0;
// 定义 x 和 y 的步长数组
npy_intp x_strides[2] = {x_dt->elsize, itemsize};
npy_intp y_strides[2] = {y_dt->elsize, itemsize};
npy_intp one = 1;
// 如果没有简单的复制循环(trivial_copy_loop 为假),则执行以下操作
if (!trivial_copy_loop) {
// 迭代器具有 NPY_ITER_ALIGNED 标志,因此无需检查输入数组的对齐方式。
// 对输入数组 op_in[2] 的数据类型和返回数据类型 ret_dt 进行转换函数的获取,
// 0 表示不进行对齐检查,将结果保存在 x_cast_info 和 transfer_flags 中。
if (PyArray_GetDTypeTransferFunction(
1, x_strides[0], x_strides[1],
PyArray_DESCR(op_in[2]), ret_dt, 0,
&x_cast_info, &transfer_flags) != NPY_SUCCEED) {
// 如果获取转换函数失败,则跳转到失败处理标签。
goto fail;
}
// 对输入数组 op_in[3] 的数据类型和返回数据类型 ret_dt 进行转换函数的获取,
// 0 表示不进行对齐检查,将结果保存在 y_cast_info 和 transfer_flags 中。
if (PyArray_GetDTypeTransferFunction(
1, y_strides[0], y_strides[1],
PyArray_DESCR(op_in[3]), ret_dt, 0,
&y_cast_info, &transfer_flags) != NPY_SUCCEED) {
// 如果获取转换函数失败,则跳转到失败处理标签。
goto fail;
}
}
// 合并 transfer_flags 和迭代器的传输标志,保存在 transfer_flags 中。
transfer_flags = PyArrayMethod_COMBINED_FLAGS(
transfer_flags, NpyIter_GetTransferFlags(iter));
// 如果 transfer_flags 不需要 Python API 支持,则启动多线程处理。
if (!(transfer_flags & NPY_METH_REQUIRES_PYAPI)) {
NPY_BEGIN_THREADS_THRESHOLDED(NpyIter_GetIterSize(iter));
}
if (NpyIter_GetIterSize(iter) != 0) {
NpyIter_IterNextFunc *iternext = NpyIter_GetIterNext(iter, NULL);
npy_intp *innersizeptr = NpyIter_GetInnerLoopSizePtr(iter);
char **dataptrarray = NpyIter_GetDataPtrArray(iter);
npy_intp *strides = NpyIter_GetInnerStrideArray(iter);
do {
npy_intp n = (*innersizeptr);
char *dst = dataptrarray[0];
char *csrc = dataptrarray[1];
char *xsrc = dataptrarray[2];
char *ysrc = dataptrarray[3];
// 迭代器可能会改变这些指针,
// 所以每次迭代都需要更新它们
npy_intp cstride = strides[1];
npy_intp xstride = strides[2];
npy_intp ystride = strides[3];
/* 常量大小,因此编译器会替换成memcpy */
if (trivial_copy_loop && itemsize == 16) {
INNER_WHERE_LOOP(16);
}
else if (trivial_copy_loop && itemsize == 8) {
INNER_WHERE_LOOP(8);
}
else if (trivial_copy_loop && itemsize == 4) {
INNER_WHERE_LOOP(4);
}
else if (trivial_copy_loop && itemsize == 2) {
INNER_WHERE_LOOP(2);
}
else if (trivial_copy_loop && itemsize == 1) {
INNER_WHERE_LOOP(1);
}
else {
npy_intp i;
for (i = 0; i < n; i++) {
if (*csrc) {
char *args[2] = {xsrc, dst};
if (x_cast_info.func(
&x_cast_info.context, args, &one,
x_strides, x_cast_info.auxdata) < 0) {
goto fail;
}
}
else {
char *args[2] = {ysrc, dst};
if (y_cast_info.func(
&y_cast_info.context, args, &one,
y_strides, y_cast_info.auxdata) < 0) {
goto fail;
}
}
dst += itemsize;
xsrc += xstride;
ysrc += ystride;
csrc += cstride;
}
}
} while (iternext(iter)); // 继续迭代直到结束
}
NPY_END_THREADS;
Py_INCREF(ret);
Py_DECREF(arr);
Py_DECREF(ax);
Py_DECREF(ay);
Py_DECREF(common_dt);
NPY_cast_info_xfree(&x_cast_info);
NPY_cast_info_xfree(&y_cast_info);
if (NpyIter_Deallocate(iter) != NPY_SUCCEED) {
Py_DECREF(ret);
return NULL;
}
return ret;
fail:
// 释放 arr 对象的引用计数
Py_DECREF(arr);
// 释放 ax 对象的引用计数
Py_XDECREF(ax);
// 释放 ay 对象的引用计数
Py_XDECREF(ay);
// 释放 common_dt 对象的引用计数
Py_XDECREF(common_dt);
// 释放 x_cast_info 结构体占用的内存
NPY_cast_info_xfree(&x_cast_info);
// 释放 y_cast_info 结构体占用的内存
NPY_cast_info_xfree(&y_cast_info);
// 返回 NULL 指针,表示函数执行失败
return NULL;
}
static PyObject *
array_where(PyObject *NPY_UNUSED(ignored), PyObject *const *args, Py_ssize_t len_args)
{
// 声明函数变量
PyObject *obj = NULL, *x = NULL, *y = NULL;
// 解析传入的参数
NPY_PREPARE_ARGPARSER;
// 如果参数解析失败,则返回 NULL 指针
if (npy_parse_arguments("where", args, len_args, NULL,
"", NULL, &obj,
"|x", NULL, &x,
"|y", NULL, &y,
NULL, NULL, NULL) < 0) {
return NULL;
}
// 调用 PyArray_Where 函数处理传入的参数并返回结果
return PyArray_Where(obj, x, y);
}
static PyObject *
array_lexsort(PyObject *NPY_UNUSED(ignored), PyObject *const *args, Py_ssize_t len_args,
PyObject *kwnames)
{
// 初始化 axis 变量为默认值 -1
int axis = -1;
// 声明 keys 对象
PyObject *obj;
// 解析传入的参数
NPY_PREPARE_ARGPARSER;
// 如果参数解析失败,则返回 NULL 指针
if (npy_parse_arguments("lexsort", args, len_args, kwnames,
"keys", NULL, &obj,
"|axis", PyArray_PythonPyIntFromInt, &axis,
NULL, NULL, NULL) < 0) {
return NULL;
}
// 调用 PyArray_LexSort 函数进行排序操作,并返回结果
return PyArray_Return((PyArrayObject *)PyArray_LexSort(obj, axis));
}
static PyObject *
array_can_cast_safely(PyObject *NPY_UNUSED(self),
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
// 声明变量
PyObject *from_obj = NULL;
PyArray_Descr *d1 = NULL;
PyArray_Descr *d2 = NULL;
int ret;
PyObject *retobj = NULL;
// 初始化 casting 变量为 NPY_SAFE_CASTING
NPY_CASTING casting = NPY_SAFE_CASTING;
// 解析传入的参数
NPY_PREPARE_ARGPARSER;
// 如果参数解析失败,则跳转到 finish 标签
if (npy_parse_arguments("can_cast", args, len_args, kwnames,
"from_", NULL, &from_obj,
"to", &PyArray_DescrConverter2, &d2,
"|casting", &PyArray_CastingConverter, &casting,
NULL, NULL, NULL) < 0) {
goto finish;
}
// 如果 d2 是 NULL 指针,则设置类型错误并跳转到 finish 标签
if (d2 == NULL) {
PyErr_SetString(PyExc_TypeError,
"did not understand one of the types; 'None' not accepted");
goto finish;
}
// 如果 from_obj 是数组对象,则使用 PyArray_CanCastArrayTo 函数进行类型转换判断
if (PyArray_Check(from_obj)) {
ret = PyArray_CanCastArrayTo((PyArrayObject *)from_obj, d2, casting);
}
else if (PyArray_IsScalar(from_obj, Generic)) {
/*
* TODO: `PyArray_IsScalar` 在新的数据类型中不应该被要求。
* weak-promotion 分支实际上与 dtype 分支相同。
*/
if (get_npy_promotion_state() == NPY_USE_WEAK_PROMOTION) {
// 获取标量对象的描述符
PyObject *descr = PyObject_GetAttr(from_obj, npy_interned_str.dtype);
if (descr == NULL) {
goto finish; // 如果获取失败,直接结束
}
if (!PyArray_DescrCheck(descr)) {
Py_DECREF(descr);
PyErr_SetString(PyExc_TypeError,
"numpy_scalar.dtype did not return a dtype instance.");
goto finish; // 如果不是有效的描述符类型,设置错误并结束
}
// 检查是否可以将描述符类型转换为目标类型
ret = PyArray_CanCastTypeTo((PyArray_Descr *)descr, d2, casting);
Py_DECREF(descr);
}
else {
/* 需要将标量对象转换为数组对象,以便考虑旧的基于值的逻辑 */
PyArrayObject *arr;
arr = (PyArrayObject *)PyArray_FROM_O(from_obj);
if (arr == NULL) {
goto finish; // 如果转换失败,直接结束
}
// 检查是否可以将数组对象转换为目标类型
ret = PyArray_CanCastArrayTo(arr, d2, casting);
Py_DECREF(arr);
}
}
else if (PyArray_IsPythonNumber(from_obj)) {
PyErr_SetString(PyExc_TypeError,
"can_cast() does not support Python ints, floats, and "
"complex because the result used to depend on the value.\n"
"This change was part of adopting NEP 50, we may "
"explicitly allow them again in the future.");
goto finish; // 不支持 Python 的整数、浮点数和复数类型,设置错误并结束
}
/* 否则使用 CanCastTypeTo */
else {
// 尝试将输入对象转换为描述符类型
if (!PyArray_DescrConverter2(from_obj, &d1) || d1 == NULL) {
PyErr_SetString(PyExc_TypeError,
"did not understand one of the types; 'None' not accepted");
goto finish; // 如果转换失败或者返回空描述符,设置错误并结束
}
// 检查是否可以将描述符类型转换为目标类型
ret = PyArray_CanCastTypeTo(d1, d2, casting);
}
// 根据返回值设置结果对象为 True 或 False
retobj = ret ? Py_True : Py_False;
Py_INCREF(retobj); // 增加结果对象的引用计数
finish:
Py_XDECREF(d1); // 释放描述符对象 d1 的引用
Py_XDECREF(d2); // 释放目标描述符对象 d2 的引用
return retobj; // 返回结果对象
static PyObject *
array_promote_types(PyObject *NPY_UNUSED(dummy), PyObject *const *args, Py_ssize_t len_args)
{
PyArray_Descr *d1 = NULL;
PyArray_Descr *d2 = NULL;
PyObject *ret = NULL;
NPY_PREPARE_ARGPARSER;
// 解析函数参数,将解析结果保存在d1和d2中
if (npy_parse_arguments("promote_types", args, len_args, NULL,
"", PyArray_DescrConverter2, &d1,
"", PyArray_DescrConverter2, &d2,
NULL, NULL, NULL) < 0) {
goto finish;
}
// 如果d1或d2为空,则设置错误并跳转到结束标签
if (d1 == NULL || d2 == NULL) {
PyErr_SetString(PyExc_TypeError,
"did not understand one of the types");
goto finish;
}
// 调用NumPy C API函数PyArray_PromoteTypes进行类型提升,并将结果保存在ret中
ret = (PyObject *)PyArray_PromoteTypes(d1, d2);
finish:
// 释放d1和d2的引用计数
Py_XDECREF(d1);
Py_XDECREF(d2);
return ret;
}
static PyObject *
array_min_scalar_type(PyObject *NPY_UNUSED(dummy), PyObject *args)
{
PyObject *array_in = NULL;
PyArrayObject *array;
PyObject *ret = NULL;
// 解析输入参数,期望一个参数,将结果保存在array_in中
if (!PyArg_ParseTuple(args, "O:min_scalar_type", &array_in)) {
return NULL;
}
// 将array_in转换为PyArrayObject对象
array = (PyArrayObject *)PyArray_FROM_O(array_in);
if (array == NULL) {
return NULL;
}
// 调用NumPy C API函数PyArray_MinScalarType获取数组的最小标量类型,并将结果保存在ret中
ret = (PyObject *)PyArray_MinScalarType(array);
// 释放array的引用计数
Py_DECREF(array);
return ret;
}
static PyObject *
array_result_type(PyObject *NPY_UNUSED(dummy), PyObject *const *args, Py_ssize_t len)
{
npy_intp i, narr = 0, ndtypes = 0;
PyArrayObject **arr = NULL;
PyArray_Descr **dtypes = NULL;
PyObject *ret = NULL;
// 如果没有输入参数,则设置错误并跳转到结束标签
if (len == 0) {
PyErr_SetString(PyExc_ValueError,
"at least one array or dtype is required");
goto finish;
}
// 分配内存以存储PyArrayObject指针和PyArray_Descr指针数组
arr = PyArray_malloc(2 * len * sizeof(void *));
if (arr == NULL) {
return PyErr_NoMemory();
}
dtypes = (PyArray_Descr**)&arr[len];
for (i = 0; i < len; ++i) {
PyObject *obj = args[i];
// 如果参数是数组对象,则增加其引用计数并存储在arr数组中
if (PyArray_Check(obj)) {
Py_INCREF(obj);
arr[narr] = (PyArrayObject *)obj;
++narr;
}
// 如果参数是标量对象或Python数值,则转换为PyArrayObject对象存储在arr数组中
else if (PyArray_IsScalar(obj, Generic) ||
PyArray_IsPythonNumber(obj)) {
arr[narr] = (PyArrayObject *)PyArray_FROM_O(obj);
if (arr[narr] == NULL) {
goto finish;
}
/*
* 如果参数是Python标量,则标记数组为临时数组
* (此时不需要实际的DType,这在ResultType函数内部会处理)
*/
npy_mark_tmp_array_if_pyscalar(obj, arr[narr], NULL);
++narr;
}
// 如果参数是描述符对象,则通过PyArray_DescrConverter函数进行转换并存储在dtypes数组中
else {
if (!PyArray_DescrConverter(obj, &dtypes[ndtypes])) {
goto finish;
}
++ndtypes;
}
}
// 调用NumPy C API函数PyArray_ResultType计算数组的结果类型,并将结果保存在ret中
ret = (PyObject *)PyArray_ResultType(narr, arr, ndtypes, dtypes);
finish:
// 释放arr数组中所有PyArrayObject对象的引用计数
for (i = 0; i < narr; ++i) {
Py_DECREF(arr[i]);
}
// 释放dtypes数组中所有PyArray_Descr对象的引用计数
for (i = 0; i < ndtypes; ++i) {
Py_DECREF(dtypes[i]);
}
// 释放arr数组的内存
PyArray_free(arr);
return ret;
}
static PyObject *
/*
* Returns datetime metadata as a tuple for a given NumPy dtype object.
* Parses arguments to extract and convert the dtype object.
* If parsing fails, returns NULL.
*/
PyObject *array_datetime_data(PyObject *NPY_UNUSED(dummy), PyObject *args)
{
PyArray_Descr *dtype;
PyArray_DatetimeMetaData *meta;
// 解析参数,获取并转换 NumPy dtype 对象
if (!PyArg_ParseTuple(args, "O&:datetime_data",
PyArray_DescrConverter, &dtype)) {
return NULL;
}
// 获取 dtype 对象的日期时间元数据
meta = get_datetime_metadata_from_dtype(dtype);
if (meta == NULL) {
Py_DECREF(dtype);
return NULL;
}
// 将日期时间元数据转换为元组并返回
PyObject *res = convert_datetime_metadata_to_tuple(meta);
Py_DECREF(dtype);
return res;
}
/*
* Converts a Python object to a TrimMode enum value.
* Checks if the object is a single-character Unicode string and assigns the corresponding TrimMode.
* If the object does not match any expected characters, raises a TypeError.
*/
static int
trimmode_converter(PyObject *obj, TrimMode *trim)
{
if (!PyUnicode_Check(obj) || PyUnicode_GetLength(obj) != 1) {
// 如果对象不是单字符 Unicode 字符串,或长度不为 1,则跳转到错误处理部分
goto error;
}
const char *trimstr = PyUnicode_AsUTF8AndSize(obj, NULL);
if (trimstr != NULL) {
// 根据字符内容设置对应的 TrimMode
if (trimstr[0] == 'k') {
*trim = TrimMode_None;
}
else if (trimstr[0] == '.') {
*trim = TrimMode_Zeros;
}
else if (trimstr[0] == '0') {
*trim = TrimMode_LeaveOneZero;
}
else if (trimstr[0] == '-') {
*trim = TrimMode_DptZeros;
}
else {
// 字符不在预期范围内,抛出类型错误异常
goto error;
}
}
return NPY_SUCCEED;
error:
PyErr_Format(PyExc_TypeError,
"if supplied, trim must be 'k', '.', '0' or '-' found `%100S`",
obj);
return NPY_FAIL;
}
/*
* Implements the Dragon4 algorithm in scientific mode for floating-point scalars.
* Parses and validates arguments related to formatting the output.
* Returns a Python object representing the formatted value.
*/
static PyObject *
dragon4_scientific(PyObject *NPY_UNUSED(dummy),
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
PyObject *obj;
int precision=-1, pad_left=-1, exp_digits=-1, min_digits=-1;
DigitMode digit_mode;
TrimMode trim = TrimMode_None;
int sign=0, unique=1;
NPY_PREPARE_ARGPARSER;
// 解析并验证参数,设置 Dragon4 算法的相关参数
if (npy_parse_arguments("dragon4_scientific", args, len_args, kwnames,
"x", NULL , &obj,
"|precision", &PyArray_PythonPyIntFromInt, &precision,
"|unique", &PyArray_PythonPyIntFromInt, &unique,
"|sign", &PyArray_PythonPyIntFromInt, &sign,
"|trim", &trimmode_converter, &trim,
"|pad_left", &PyArray_PythonPyIntFromInt, &pad_left,
"|exp_digits", &PyArray_PythonPyIntFromInt, &exp_digits,
"|min_digits", &PyArray_PythonPyIntFromInt, &min_digits,
NULL, NULL, NULL) < 0) {
return NULL;
}
digit_mode = unique ? DigitMode_Unique : DigitMode_Exact;
// 在非唯一模式下,如果未提供精度参数,抛出类型错误异常
if (unique == 0 && precision < 0) {
PyErr_SetString(PyExc_TypeError,
"in non-unique mode `precision` must be supplied");
return NULL;
}
// 调用 Dragon4 算法,返回格式化后的结果对象
return Dragon4_Scientific(obj, digit_mode, precision, min_digits, sign, trim,
pad_left, exp_digits);
}
/*
* 使用 Dragon4 算法以位置模式打印浮点数标量。
* 参见 `np.format_float_positional` 的文档字符串以获取参数描述。
* 不同之处在于 pad_left、pad_right、precision 的值为 -1 表示未指定,等效于 `None`。
*/
static PyObject *
dragon4_positional(PyObject *NPY_UNUSED(dummy),
PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
{
PyObject *obj;
int precision=-1, pad_left=-1, pad_right=-1, min_digits=-1;
CutoffMode cutoff_mode;
DigitMode digit_mode;
TrimMode trim = TrimMode_None;
int sign=0, unique=1, fractional=0;
NPY_PREPARE_ARGPARSER;
// 解析函数参数
if (npy_parse_arguments("dragon4_positional", args, len_args, kwnames,
"x", NULL , &obj,
"|precision", &PyArray_PythonPyIntFromInt, &precision,
"|unique", &PyArray_PythonPyIntFromInt, &unique,
"|fractional", &PyArray_PythonPyIntFromInt, &fractional,
"|sign", &PyArray_PythonPyIntFromInt, &sign,
"|trim", &trimmode_converter, &trim,
"|pad_left", &PyArray_PythonPyIntFromInt, &pad_left,
"|pad_right", &PyArray_PythonPyIntFromInt, &pad_right,
"|min_digits", &PyArray_PythonPyIntFromInt, &min_digits,
NULL, NULL, NULL) < 0) {
return NULL;
}
// 根据 unique 的值确定 digit_mode
digit_mode = unique ? DigitMode_Unique : DigitMode_Exact;
// 根据 fractional 的值确定 cutoff_mode
cutoff_mode = fractional ? CutoffMode_FractionLength :
CutoffMode_TotalLength;
// 在非 unique 模式下,如果未提供 precision,报错
if (unique == 0 && precision < 0) {
PyErr_SetString(PyExc_TypeError,
"in non-unique mode `precision` must be supplied");
return NULL;
}
// 调用 Dragon4_Positional 函数处理参数并返回结果
return Dragon4_Positional(obj, digit_mode, cutoff_mode, precision,
min_digits, sign, trim, pad_left, pad_right);
}
/*
* 格式化长浮点数对象。
* 要求精度值 precision,参见 `obj` 的类型为 LongDouble。
*/
static PyObject *
format_longfloat(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds)
{
PyObject *obj;
unsigned int precision;
static char *kwlist[] = {"x", "precision", NULL};
// 解析参数列表
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OI:format_longfloat", kwlist,
&obj, &precision)) {
return NULL;
}
// 如果 obj 不是 LongDouble 类型,则报错
if (!PyArray_IsScalar(obj, LongDouble)) {
PyErr_SetString(PyExc_TypeError,
"not a longfloat");
return NULL;
}
// 调用 Dragon4_Scientific 函数处理参数并返回结果
return Dragon4_Scientific(obj, DigitMode_Unique, precision, -1, 0,
TrimMode_LeaveOneZero, -1, -1);
}
/*
* 检查数组是否是用户定义的字符串数据类型。
* 如果是,则返回 1;否则设置错误并返回 0。
*/
static int _is_user_defined_string_array(PyArrayObject* array)
{
// 省略部分代码
}
if (NPY_DT_is_user_defined(PyArray_DESCR(array))) {
PyTypeObject* scalar_type = NPY_DTYPE(PyArray_DESCR(array))->scalar_type;
if (PyType_IsSubtype(scalar_type, &PyBytes_Type) ||
PyType_IsSubtype(scalar_type, &PyUnicode_Type)) {
return 1;
}
else {
PyErr_SetString(
PyExc_TypeError,
"string comparisons are only allowed for dtypes with a "
"scalar type that is a subtype of str or bytes.");
return 0;
}
}
else {
PyErr_SetString(
PyExc_TypeError,
"string operation on non-string array");
return 0;
}
/*
* The only purpose of this function is that it allows the "rstrip".
* From my (@seberg's) perspective, this function should be deprecated
* and I do not think it matters if it is not particularly fast.
*/
static PyObject *
compare_chararrays(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds)
{
PyObject *array;
PyObject *other;
PyArrayObject *newarr, *newoth;
int cmp_op;
npy_bool rstrip;
char *cmp_str;
Py_ssize_t strlength;
PyObject *res = NULL;
static char msg[] = "comparison must be '==', '!=', '<', '>', '<=', '>='";
static char *kwlist[] = {"a1", "a2", "cmp", "rstrip", NULL};
// 解析传入的参数和关键字参数,设置关键字列表
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOs#O&:compare_chararrays",
kwlist,
&array, &other, &cmp_str, &strlength,
PyArray_BoolConverter, &rstrip)) {
return NULL;
}
// 检查比较操作符字符串长度的有效性
if (strlength < 1 || strlength > 2) {
goto err;
}
// 根据比较操作符字符串长度的不同,确定比较操作符类型
if (strlength > 1) {
if (cmp_str[1] != '=') {
goto err;
}
if (cmp_str[0] == '=') {
cmp_op = Py_EQ;
}
else if (cmp_str[0] == '!') {
cmp_op = Py_NE;
}
else if (cmp_str[0] == '<') {
cmp_op = Py_LE;
}
else if (cmp_str[0] == '>') {
cmp_op = Py_GE;
}
else {
goto err;
}
}
else {
if (cmp_str[0] == '<') {
cmp_op = Py_LT;
}
else if (cmp_str[0] == '>') {
cmp_op = Py_GT;
}
else {
goto err;
}
}
// 将输入参数转换为 NumPy 数组对象
newarr = (PyArrayObject *)PyArray_FROM_O(array);
if (newarr == NULL) {
return NULL;
}
newoth = (PyArrayObject *)PyArray_FROM_O(other);
if (newoth == NULL) {
Py_DECREF(newarr);
return NULL;
}
// 如果输入的数组都是字符串数组,则调用字符串比较函数
if (PyArray_ISSTRING(newarr) && PyArray_ISSTRING(newoth)) {
res = _umath_strings_richcompare(newarr, newoth, cmp_op, rstrip != 0);
}
else {
// 如果输入的数组不是字符串数组,则抛出类型错误异常
PyErr_SetString(PyExc_TypeError,
"comparison of non-string arrays");
Py_DECREF(newarr);
Py_DECREF(newoth);
return NULL;
}
// 释放数组对象的引用计数
Py_DECREF(newarr);
Py_DECREF(newoth);
return res;
err:
// 如果出现错误,设置值错误异常并返回 NULL
PyErr_SetString(PyExc_ValueError, msg);
return NULL;
}
static PyObject *
_vec_string_with_args(PyArrayObject* char_array, PyArray_Descr* type,
PyObject* method, PyObject* args)
{
PyObject* broadcast_args[NPY_MAXARGS];
PyArrayMultiIterObject* in_iter = NULL;
PyArrayObject* result = NULL;
PyArrayIterObject* out_iter = NULL;
Py_ssize_t i, n, nargs;
// 计算参数序列的长度,并检查其有效性
nargs = PySequence_Size(args) + 1;
if (nargs == -1 || nargs > NPY_MAXARGS) {
PyErr_Format(PyExc_ValueError,
"len(args) must be < %d", NPY_MAXARGS - 1);
Py_DECREF(type);
goto err;
}
// 将第一个参数设置为输入的字符数组对象
broadcast_args[0] = (PyObject*)char_array;
for (i = 1; i < nargs; i++) {
// 从参数元组中获取第 i-1 个参数对象
PyObject* item = PySequence_GetItem(args, i-1);
// 如果获取失败,释放之前申请的 type 对象并跳转到错误处理标签 err
if (item == NULL) {
Py_DECREF(type);
goto err;
}
// 将获取的参数对象保存到 broadcast_args 数组中
broadcast_args[i] = item;
// 释放参数对象的引用计数
Py_DECREF(item);
}
// 根据 broadcast_args 数组创建多迭代器对象 in_iter
in_iter = (PyArrayMultiIterObject*)PyArray_MultiIterFromObjects
(broadcast_args, nargs, 0);
// 如果创建失败,释放之前申请的 type 对象并跳转到错误处理标签 err
if (in_iter == NULL) {
Py_DECREF(type);
goto err;
}
// 获取 in_iter 中的迭代器数量
n = in_iter->numiter;
// 根据 in_iter 的维度和类型创建新的 PyArrayObject 对象 result
result = (PyArrayObject*)PyArray_SimpleNewFromDescr(in_iter->nd,
in_iter->dimensions, type);
// 如果创建失败,跳转到错误处理标签 err
if (result == NULL) {
goto err;
}
// 根据 result 创建输出迭代器对象 out_iter
out_iter = (PyArrayIterObject*)PyArray_IterNew((PyObject*)result);
// 如果创建失败,跳转到错误处理标签 err
if (out_iter == NULL) {
goto err;
}
// 循环处理多迭代器 in_iter 中的元素
while (PyArray_MultiIter_NOTDONE(in_iter)) {
PyObject* item_result;
// 创建一个包含 n 个元素的元组 args_tuple
PyObject* args_tuple = PyTuple_New(n);
// 如果创建失败,跳转到错误处理标签 err
if (args_tuple == NULL) {
goto err;
}
// 遍历 in_iter 的迭代器并将每个元素转换为标量对象存入 args_tuple 中
for (i = 0; i < n; i++) {
PyArrayIterObject* it = in_iter->iters[i];
PyObject* arg = PyArray_ToScalar(PyArray_ITER_DATA(it), it->ao);
// 如果转换失败,释放 args_tuple 并跳转到错误处理标签 err
if (arg == NULL) {
Py_DECREF(args_tuple);
goto err;
}
/* Steals ref to arg */
// 将 arg 添加到 args_tuple 中,注意 PyTuple_SetItem 会接管 arg 的引用计数
PyTuple_SetItem(args_tuple, i, arg);
}
// 调用 method 对象,并传入 args_tuple 中的参数进行计算
item_result = PyObject_CallObject(method, args_tuple);
// 释放 args_tuple 对象的引用计数
Py_DECREF(args_tuple);
// 如果调用失败,跳转到错误处理标签 err
if (item_result == NULL) {
goto err;
}
// 将 item_result 存入 result 的当前迭代位置
if (PyArray_SETITEM(result, PyArray_ITER_DATA(out_iter), item_result)) {
// 释放 item_result 对象
Py_DECREF(item_result);
// 设置错误信息并跳转到错误处理标签 err
PyErr_SetString( PyExc_TypeError,
"result array type does not match underlying function");
goto err;
}
// 释放 item_result 对象的引用计数
Py_DECREF(item_result);
// 移动 in_iter 和 out_iter 到下一个元素
PyArray_MultiIter_NEXT(in_iter);
PyArray_ITER_NEXT(out_iter);
}
// 释放 in_iter 和 out_iter 对象的引用计数
Py_DECREF(in_iter);
Py_DECREF(out_iter);
// 返回 result 对象作为函数执行的结果
return (PyObject*)result;
err:
// 释放 in_iter、out_iter 和 result 对象的引用计数
Py_XDECREF(in_iter);
Py_XDECREF(out_iter);
Py_XDECREF(result);
// 返回 0 表示函数执行失败
return 0;
static PyObject *
_vec_string_no_args(PyArrayObject* char_array,
PyArray_Descr* type, PyObject* method)
{
/*
* This is a faster version of _vec_string_args to use when there
* are no additional arguments to the string method. This doesn't
* require a broadcast iterator (and broadcast iterators don't work
* with 1 argument anyway).
*/
// 初始化输入迭代器和输出结果对象的迭代器为NULL
PyArrayIterObject* in_iter = NULL;
PyArrayObject* result = NULL;
PyArrayIterObject* out_iter = NULL;
// 创建输入迭代器,如果失败则跳转到错误处理
in_iter = (PyArrayIterObject*)PyArray_IterNew((PyObject*)char_array);
if (in_iter == NULL) {
Py_DECREF(type);
goto err;
}
// 根据给定的描述符创建结果数组对象,如果失败则跳转到错误处理
result = (PyArrayObject*)PyArray_SimpleNewFromDescr(
PyArray_NDIM(char_array), PyArray_DIMS(char_array), type);
if (result == NULL) {
goto err;
}
// 创建输出结果对象的迭代器,如果失败则跳转到错误处理
out_iter = (PyArrayIterObject*)PyArray_IterNew((PyObject*)result);
if (out_iter == NULL) {
goto err;
}
// 迭代处理输入数组中的每个元素
while (PyArray_ITER_NOTDONE(in_iter)) {
PyObject* item_result;
PyObject* item = PyArray_ToScalar(in_iter->dataptr, in_iter->ao);
if (item == NULL) {
goto err;
}
// 调用给定的方法处理当前元素,如果失败则跳转到错误处理
item_result = PyObject_CallFunctionObjArgs(method, item, NULL);
Py_DECREF(item);
if (item_result == NULL) {
goto err;
}
// 将处理结果放入输出数组中的当前位置,如果类型不匹配则设置错误信息并跳转到错误处理
if (PyArray_SETITEM(result, PyArray_ITER_DATA(out_iter), item_result)) {
Py_DECREF(item_result);
PyErr_SetString( PyExc_TypeError,
"result array type does not match underlying function");
goto err;
}
Py_DECREF(item_result);
// 移动到下一个输入和输出数组的位置
PyArray_ITER_NEXT(in_iter);
PyArray_ITER_NEXT(out_iter);
}
// 释放迭代器对象
Py_DECREF(in_iter);
Py_DECREF(out_iter);
// 返回处理结果数组对象
return (PyObject*)result;
err:
// 出错时释放所有可能已分配的资源,并返回0
Py_XDECREF(in_iter);
Py_XDECREF(out_iter);
Py_XDECREF(result);
return 0;
}
else {
// 如果条件不成立,则执行以下操作
if (_is_user_defined_string_array(char_array)) {
// 检查 char_array 是否为用户定义的字符串数组,若是,则执行以下操作
PyTypeObject* scalar_type =
NPY_DTYPE(PyArray_DESCR(char_array))->scalar_type;
// 获取 char_array 对应的数据类型描述符的标量类型
method = PyObject_GetAttr((PyObject*)scalar_type, method_name);
// 获取标量类型对应的方法对象
}
else {
// 如果不是用户定义的字符串数组,则执行以下操作
Py_DECREF(type);
// 减少对 type 的引用计数
goto err;
// 跳转到错误处理部分
}
}
if (method == NULL) {
// 如果 method 为 NULL,则执行以下操作
Py_DECREF(type);
// 减少对 type 的引用计数
goto err;
// 跳转到错误处理部分
}
if (args_seq == NULL
|| (PySequence_Check(args_seq) && PySequence_Size(args_seq) == 0)) {
// 如果 args_seq 为 NULL 或者是一个空序列,则执行以下操作
result = _vec_string_no_args(char_array, type, method);
// 调用 _vec_string_no_args 函数,处理没有参数的情况
}
else if (PySequence_Check(args_seq)) {
// 如果 args_seq 是一个序列,则执行以下操作
result = _vec_string_with_args(char_array, type, method, args_seq);
// 调用 _vec_string_with_args 函数,处理带有参数的情况
}
else {
// 如果 args_seq 不是一个序列,则执行以下操作
Py_DECREF(type);
// 减少对 type 的引用计数
PyErr_SetString(PyExc_TypeError,
"'args' must be a sequence of arguments");
// 设置一个类型错误的异常字符串
goto err;
// 跳转到错误处理部分
}
if (result == NULL) {
// 如果 result 为 NULL,则执行以下操作
goto err;
// 跳转到错误处理部分
}
Py_DECREF(char_array);
// 减少对 char_array 的引用计数
Py_DECREF(method);
// 减少对 method 的引用计数
return (PyObject*)result;
// 返回 result 对象的 PyObject 指针
err:
// 错误处理部分
Py_XDECREF(char_array);
// 减少或清除 char_array 的引用计数
Py_XDECREF(method);
// 减少或清除 method 的引用计数
return 0;
// 返回 0,表示函数执行失败
static PyObject *
array_shares_memory_impl(PyObject *args, PyObject *kwds, Py_ssize_t default_max_work,
int raise_exceptions)
{
PyObject * self_obj = NULL; // 定义指向第一个数组对象的 Python 对象指针
PyObject * other_obj = NULL; // 定义指向第二个数组对象的 Python 对象指针
PyArrayObject * self = NULL; // 定义指向第一个数组对象的 NumPy 数组对象指针
PyArrayObject * other = NULL; // 定义指向第二个数组对象的 NumPy 数组对象指针
PyObject *max_work_obj = NULL; // 定义指向 max_work 参数的 Python 对象指针
static char *kwlist[] = {"self", "other", "max_work", NULL}; // 定义关键字列表,用于参数解析
mem_overlap_t result; // 定义存储内存重叠检测结果的变量
Py_ssize_t max_work; // 定义存储最大工作单元数的变量
NPY_BEGIN_THREADS_DEF; // 定义 NumPy 线程处理开始的宏
max_work = default_max_work; // 将默认最大工作单元数赋值给 max_work
// 解析传入的参数
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O:shares_memory_impl", kwlist,
&self_obj, &other_obj, &max_work_obj)) {
return NULL; // 参数解析失败时返回空指针
}
// 检查第一个对象是否为 NumPy 数组
if (PyArray_Check(self_obj)) {
self = (PyArrayObject*)self_obj; // 将 self_obj 转换为 PyArrayObject 指针
Py_INCREF(self); // 增加 self 的引用计数
}
else {
/* Use FromAny to enable checking overlap for objects exposing array
interfaces etc. */
self = (PyArrayObject*)PyArray_FROM_O(self_obj); // 使用 PyArray_FROM_O 转换对象
if (self == NULL) {
goto fail; // 转换失败时跳转到 fail 标签处理错误
}
}
// 检查第二个对象是否为 NumPy 数组
if (PyArray_Check(other_obj)) {
other = (PyArrayObject*)other_obj; // 将 other_obj 转换为 PyArrayObject 指针
Py_INCREF(other); // 增加 other 的引用计数
}
else {
other = (PyArrayObject*)PyArray_FROM_O(other_obj); // 使用 PyArray_FROM_O 转换对象
if (other == NULL) {
goto fail; // 转换失败时跳转到 fail 标签处理错误
}
}
// 处理 max_work_obj 参数
if (max_work_obj == NULL || max_work_obj == Py_None) {
/* noop */ // 如果 max_work_obj 为空或者为 None,则什么都不做
}
else if (PyLong_Check(max_work_obj)) {
max_work = PyLong_AsSsize_t(max_work_obj); // 将 max_work_obj 转换为 Py_ssize_t 类型
if (PyErr_Occurred()) {
goto fail; // 转换过程中出错时跳转到 fail 标签处理错误
}
}
else {
PyErr_SetString(PyExc_ValueError, "max_work must be an integer"); // 设置错误信息
goto fail; // 跳转到 fail 标签处理错误
}
// 检查 max_work 的值是否合法
if (max_work < -2) {
PyErr_SetString(PyExc_ValueError, "Invalid value for max_work"); // 设置错误信息
goto fail; // 跳转到 fail 标签处理错误
}
NPY_BEGIN_THREADS; // 开始 NumPy 线程处理
// 调用 solve_may_share_memory 函数进行内存重叠检测
result = solve_may_share_memory(self, other, max_work);
NPY_END_THREADS; // 结束 NumPy 线程处理
Py_XDECREF(self); // 释放 self 对象的引用
Py_XDECREF(other); // 释放 other 对象的引用
// 根据检测结果返回相应的 Python 对象
if (result == MEM_OVERLAP_NO) {
Py_RETURN_FALSE; // 返回 Python 中的 False
}
else if (result == MEM_OVERLAP_YES) {
Py_RETURN_TRUE; // 返回 Python 中的 True
}
else if (result == MEM_OVERLAP_OVERFLOW) {
if (raise_exceptions) {
PyErr_SetString(PyExc_OverflowError,
"Integer overflow in computing overlap"); // 设置错误信息
return NULL; // 返回空指针
}
else {
/* Don't know, so say yes */
Py_RETURN_TRUE; // 不确定时,默认返回 Python 中的 True
}
}
else if (result == MEM_OVERLAP_TOO_HARD) {
if (raise_exceptions) {
PyErr_SetString(npy_static_pydata.TooHardError,
"Exceeded max_work"); // 设置错误信息
return NULL; // 返回空指针
}
else {
/* Don't know, so say yes */
Py_RETURN_TRUE; // 不确定时,默认返回 Python 中的 True
}
}
else {
/* Doesn't happen usually */
PyErr_SetString(PyExc_RuntimeError,
"Error in computing overlap"); // 设置错误信息
return NULL; // 返回空指针
}
fail:
Py_XDECREF(self); // 处理错误时释放 self 对象的引用
Py_XDECREF(other); // 处理错误时释放 other 对象的引用
return NULL; // 返回空指针
}
static PyObjectc
// 定义函数 `array_shares_memory`,接收三个参数:无用参数 `ignored`,`args` 和 `kwds`
{
// 调用 `array_shares_memory_impl` 函数,使用参数 `args` 和 `kwds`,指定共享内存的精确性标志为 `NPY_MAY_SHARE_EXACT`,并返回结果
return array_shares_memory_impl(args, kwds, NPY_MAY_SHARE_EXACT, 1);
}
// 定义静态函数 `array_may_share_memory`,接收三个参数:无用参数 `ignored`,`args` 和 `kwds`
{
// 调用 `array_shares_memory_impl` 函数,使用参数 `args` 和 `kwds`,指定共享内存的边界标志为 `NPY_MAY_SHARE_BOUNDS`,并返回结果
return array_shares_memory_impl(args, kwds, NPY_MAY_SHARE_BOUNDS, 0);
}
// 定义静态函数 `normalize_axis_index`,接收四个参数:无用参数 `self`,`args` 数组,`len_args` 参数数组长度,`kwnames` 关键字参数
{
// 声明整型变量 `axis` 和 `ndim`
int axis;
int ndim;
// 声明对象 `msg_prefix`,初始化为 `Py_None`
PyObject *msg_prefix = Py_None;
// 定义宏 `NPY_PREPARE_ARGPARSER`,准备解析函数参数
// 解析参数,如果解析失败则返回 `NULL`
if (npy_parse_arguments("normalize_axis_index", args, len_args, kwnames,
"axis", &PyArray_PythonPyIntFromInt, &axis,
"ndim", &PyArray_PythonPyIntFromInt, &ndim,
"|msg_prefix", NULL, &msg_prefix,
NULL, NULL, NULL) < 0) {
return NULL;
}
// 检查和调整 `axis`,如果失败则返回 `NULL`
if (check_and_adjust_axis_msg(&axis, ndim, msg_prefix) < 0) {
return NULL;
}
// 返回 `axis` 的 `PyLong` 对象
return PyLong_FromLong(axis);
}
// 定义静态函数 `_set_numpy_warn_if_no_mem_policy`,接收两个参数:无用参数 `self` 和 `arg`
{
// 判断 `arg` 是否为真值,失败则返回 `NULL`
int res = PyObject_IsTrue(arg);
if (res < 0) {
return NULL;
}
// 保存 `npy_thread_unsafe_state.warn_if_no_mem_policy` 的旧值
int old_value = npy_thread_unsafe_state.warn_if_no_mem_policy;
// 设置 `npy_thread_unsafe_state.warn_if_no_mem_policy` 为 `res` 的值
npy_thread_unsafe_state.warn_if_no_mem_policy = res;
// 如果旧值为真,返回 `True`;否则返回 `False`
if (old_value) {
Py_RETURN_TRUE;
}
else {
Py_RETURN_FALSE;
}
}
// 定义静态函数 `_reload_guard`,接收两个参数:无用参数 `self` 和 `args`
{
// 如果不是 PyPy 版本,并且当前解释器不是主解释器状态
if (PyThreadState_Get()->interp != PyInterpreterState_Main()) {
// 发出警告,说明 NumPy 是从 Python 的子解释器中导入的,而 NumPy 并不完全支持子解释器
// 设置 `npy_thread_unsafe_state.reload_guard_initialized` 为 1
// 返回 `None`
if (PyErr_WarnEx(PyExc_UserWarning,
"NumPy was imported from a Python sub-interpreter but "
"NumPy does not properly support sub-interpreters. "
"This will likely work for most users but might cause hard to "
"track down issues or subtle bugs. "
"A common user of the rare sub-interpreter feature is wsgi "
"which also allows single-interpreter mode.\n"
"Improvements in the case of bugs are welcome, but is not "
"on the NumPy roadmap, and full support may require "
"significant effort to achieve.", 2) < 0) {
return NULL;
}
// 返回 `None`
npy_thread_unsafe_state.reload_guard_initialized = 1;
Py_RETURN_NONE;
}
// 如果 `npy_thread_unsafe_state.reload_guard_initialized` 已经初始化
if (npy_thread_unsafe_state.reload_guard_initialized) {
// 发出警告,说明 NumPy 模块被重新加载(第二次导入)
// 返回 `None`
if (PyErr_WarnEx(PyExc_UserWarning,
"The NumPy module was reloaded (imported a second time). "
"This can in some cases result in small but subtle issues "
"and is discouraged.", 2) < 0) {
return NULL;
}
}
// 设置 `npy_thread_unsafe_state.reload_guard_initialized` 为 1
// 返回 `None`
npy_thread_unsafe_state.reload_guard_initialized = 1;
Py_RETURN_NONE;
}
// 定义静态结构体 `array_module_methods`,包含一系列方法定义
{"_get_implementing_args",
(PyCFunction)array__get_implementing_args,
METH_VARARGS, NULL},
{"_get_ndarray_c_version",
(PyCFunction)array__get_ndarray_c_version,
METH_NOARGS, NULL},
{"_reconstruct",
(PyCFunction)array__reconstruct,
METH_VARARGS, NULL},
{"set_datetimeparse_function",
(PyCFunction)array_set_datetimeparse_function,
METH_VARARGS|METH_KEYWORDS, NULL},
{"set_typeDict",
(PyCFunction)array_set_typeDict,
METH_VARARGS, NULL},
{"array",
(PyCFunction)array_array,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"asarray",
(PyCFunction)array_asarray,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"asanyarray",
(PyCFunction)array_asanyarray,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"ascontiguousarray",
(PyCFunction)array_ascontiguousarray,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"asfortranarray",
(PyCFunction)array_asfortranarray,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"copyto",
(PyCFunction)array_copyto,
METH_VARARGS|METH_KEYWORDS, NULL},
{"nested_iters",
(PyCFunction)NpyIter_NestedIters,
METH_VARARGS|METH_KEYWORDS, NULL},
{"arange",
(PyCFunction)array_arange,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"zeros",
(PyCFunction)array_zeros,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"count_nonzero",
(PyCFunction)array_count_nonzero,
METH_FASTCALL, NULL},
{"empty",
(PyCFunction)array_empty,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"empty_like",
(PyCFunction)array_empty_like,
METH_FASTCALL|METH_KEYWORDS, NULL},
{"scalar",
(PyCFunction)array_scalar,
METH_VARARGS|METH_KEYWORDS, NULL},
{"where",
(PyCFunction)array_where,
METH_FASTCALL, NULL},
{"lexsort",
(PyCFunction)array_lexsort,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"putmask",
(PyCFunction)array_putmask,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"fromstring",
(PyCFunction)array_fromstring,
METH_VARARGS|METH_KEYWORDS, NULL},
{"fromiter",
(PyCFunction)array_fromiter,
METH_VARARGS|METH_KEYWORDS, NULL},
{"concatenate",
(PyCFunction)array_concatenate,
METH_FASTCALL|METH_KEYWORDS, NULL},
{"inner",
(PyCFunction)array_innerproduct,
METH_FASTCALL, NULL},
{"dot",
(PyCFunction)array_matrixproduct,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"vdot",
(PyCFunction)array_vdot,
METH_FASTCALL, NULL},
{"c_einsum",
(PyCFunction)array_einsum,
METH_VARARGS|METH_KEYWORDS, NULL},
{"correlate",
(PyCFunction)array_correlate,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"correlate2",
(PyCFunction)array_correlate2,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"frombuffer",
(PyCFunction)array_frombuffer,
METH_VARARGS | METH_KEYWORDS, NULL},
{"fromfile",
(PyCFunction)array_fromfile,
METH_VARARGS | METH_KEYWORDS, NULL},
{"can_cast",
(PyCFunction)array_can_cast_safely,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"promote_types",
(PyCFunction)array_promote_types,
METH_FASTCALL, NULL},
{"min_scalar_type",
(PyCFunction)array_min_scalar_type,
METH_VARARGS, NULL},
{"result_type",
(PyCFunction)array_result_type,
METH_FASTCALL, NULL},
{"shares_memory",
(PyCFunction)array_shares_memory,
METH_VARARGS | METH_KEYWORDS, NULL},
{"may_share_memory",
(PyCFunction)array_may_share_memory,
METH_VARARGS | METH_KEYWORDS, NULL},
/* Datetime-related functions */
{"datetime_data",
(PyCFunction)array_datetime_data,
METH_VARARGS, NULL},
{"datetime_as_string",
(PyCFunction)array_datetime_as_string,
METH_VARARGS | METH_KEYWORDS, NULL},
/* Datetime business-day API */
{"busday_offset",
(PyCFunction)array_busday_offset,
METH_VARARGS | METH_KEYWORDS, NULL},
{"busday_count",
(PyCFunction)array_busday_count,
METH_VARARGS | METH_KEYWORDS, NULL},
{"is_busday",
(PyCFunction)array_is_busday,
METH_VARARGS | METH_KEYWORDS, NULL},
{"format_longfloat",
(PyCFunction)format_longfloat,
METH_VARARGS | METH_KEYWORDS, NULL},
{"dragon4_positional",
(PyCFunction)dragon4_positional,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"dragon4_scientific",
(PyCFunction)dragon4_scientific,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"compare_chararrays",
(PyCFunction)compare_chararrays,
METH_VARARGS | METH_KEYWORDS, NULL},
{"_vec_string",
(PyCFunction)_vec_string,
METH_VARARGS | METH_KEYWORDS, NULL},
{"_place", (PyCFunction)arr_place,
METH_VARARGS | METH_KEYWORDS,
"Insert vals sequentially into equivalent 1-d positions "
"indicated by mask."},
{"bincount", (PyCFunction)arr_bincount,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"_monotonicity", (PyCFunction)arr__monotonicity,
METH_VARARGS | METH_KEYWORDS, NULL},
{"interp", (PyCFunction)arr_interp,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"interp_complex", (PyCFunction)arr_interp_complex,
METH_FASTCALL | METH_KEYWORDS, NULL},
{"ravel_multi_index", (PyCFunction)arr_ravel_multi_index,
METH_VARARGS | METH_KEYWORDS, NULL},
{"unravel
{"normalize_axis_index", (PyCFunction)normalize_axis_index,
METH_FASTCALL | METH_KEYWORDS, NULL},
# 定义名为 "normalize_axis_index" 的 C 函数,使用 METH_FASTCALL 和 METH_KEYWORDS 标志
{"set_legacy_print_mode", (PyCFunction)set_legacy_print_mode,
METH_VARARGS, NULL},
# 定义名为 "set_legacy_print_mode" 的 C 函数,使用 METH_VARARGS 标志
{"_discover_array_parameters", (PyCFunction)_discover_array_parameters,
METH_FASTCALL | METH_KEYWORDS, NULL},
# 定义名为 "_discover_array_parameters" 的 C 函数,使用 METH_FASTCALL 和 METH_KEYWORDS 标志
{"_get_castingimpl", (PyCFunction)_get_castingimpl,
METH_VARARGS | METH_KEYWORDS, NULL},
# 定义名为 "_get_castingimpl" 的 C 函数,使用 METH_VARARGS 和 METH_KEYWORDS 标志
{"_load_from_filelike", (PyCFunction)_load_from_filelike,
METH_FASTCALL | METH_KEYWORDS, NULL},
# 定义名为 "_load_from_filelike" 的 C 函数,使用 METH_FASTCALL 和 METH_KEYWORDS 标志
/* from umath */
# 以下几行是注释,说明接下来的函数来自 umath 模块
{"frompyfunc",
(PyCFunction) ufunc_frompyfunc,
METH_VARARGS | METH_KEYWORDS, NULL},
# 定义名为 "frompyfunc" 的 C 函数,使用 METH_VARARGS 和 METH_KEYWORDS 标志
{"_make_extobj",
(PyCFunction)extobj_make_extobj,
METH_FASTCALL | METH_KEYWORDS, NULL},
# 定义名为 "_make_extobj" 的 C 函数,使用 METH_FASTCALL 和 METH_KEYWORDS 标志
{"_get_extobj_dict",
(PyCFunction)extobj_get_extobj_dict,
METH_NOARGS, NULL},
# 定义名为 "_get_extobj_dict" 的 C 函数,使用 METH_NOARGS 标志
{"get_handler_name",
(PyCFunction) get_handler_name,
METH_VARARGS, NULL},
# 定义名为 "get_handler_name" 的 C 函数,使用 METH_VARARGS 标志
{"get_handler_version",
(PyCFunction) get_handler_version,
METH_VARARGS, NULL},
# 定义名为 "get_handler_version" 的 C 函数,使用 METH_VARARGS 标志
{"_get_promotion_state",
(PyCFunction)npy__get_promotion_state,
METH_NOARGS, "Get the current NEP 50 promotion state."},
# 定义名为 "_get_promotion_state" 的 C 函数,使用 METH_NOARGS 标志,附带说明字符串
{"_set_promotion_state",
(PyCFunction)npy__set_promotion_state,
METH_O, "Set the NEP 50 promotion state. This is not thread-safe.\n"
"The optional warnings can be safely silenced using the \n"
"`np._no_nep50_warning()` context manager."},
# 定义名为 "_set_promotion_state" 的 C 函数,使用 METH_O 标志,附带详细说明字符串
{"_set_numpy_warn_if_no_mem_policy",
(PyCFunction)_set_numpy_warn_if_no_mem_policy,
METH_O, "Change the warn if no mem policy flag for testing."},
# 定义名为 "_set_numpy_warn_if_no_mem_policy" 的 C 函数,使用 METH_O 标志,附带简要说明字符串
{"_add_newdoc_ufunc", (PyCFunction)add_newdoc_ufunc,
METH_VARARGS, NULL},
# 定义名为 "_add_newdoc_ufunc" 的 C 函数,使用 METH_VARARGS 标志
{"_get_sfloat_dtype",
get_sfloat_dtype, METH_NOARGS, NULL},
# 定义名为 "_get_sfloat_dtype" 的 C 函数,使用 METH_NOARGS 标志
{"_get_madvise_hugepage", (PyCFunction)_get_madvise_hugepage,
METH_NOARGS, NULL},
# 定义名为 "_get_madvise_hugepage" 的 C 函数,使用 METH_NOARGS 标志
{"_set_madvise_hugepage", (PyCFunction)_set_madvise_hugepage,
METH_O, NULL},
# 定义名为 "_set_madvise_hugepage" 的 C 函数,使用 METH_O 标志
{"_reload_guard", (PyCFunction)_reload_guard,
METH_NOARGS,
"Give a warning on reload and big warning in sub-interpreters."},
# 定义名为 "_reload_guard" 的 C 函数,使用 METH_NOARGS 标志,附带详细说明字符串
{"from_dlpack", (PyCFunction)from_dlpack,
METH_FASTCALL | METH_KEYWORDS, NULL},
# 定义名为 "from_dlpack" 的 C 函数,使用 METH_FASTCALL 和 METH_KEYWORDS 标志
{NULL, NULL, 0, NULL} /* sentinel */
# 最后一个条目,标志着结尾的 sentinel,不定义任何函数
/* Establish scalar-type hierarchy
*
* For dual inheritance we need to make sure that the objects being
* inherited from have the tp->mro object initialized. This is
* not necessarily true for the basic type objects of Python (it is
* checked for single inheritance but not dual in PyType_Ready).
*
* Thus, we call PyType_Ready on the standard Python Types, here.
*/
static int
setup_scalartypes(PyObject *NPY_UNUSED(dict))
{
// 检查并初始化标准 Python 类型对象,确保可以进行双重继承
if (PyType_Ready(&PyBool_Type) < 0) {
return -1;
}
if (PyType_Ready(&PyFloat_Type) < 0) {
return -1;
}
if (PyType_Ready(&PyComplex_Type) < 0) {
return -1;
}
if (PyType_Ready(&PyBytes_Type) < 0) {
return -1;
}
if (PyType_Ready(&PyUnicode_Type) < 0) {
return -1;
}
#define SINGLE_INHERIT(child, parent) \
// 设置单一继承关系宏,初始化子类的类型对象
Py##child##ArrType_Type.tp_base = &Py##parent##ArrType_Type; \
if (PyType_Ready(&Py##child##ArrType_Type) < 0) { \
PyErr_Print(); \
PyErr_Format(PyExc_SystemError, \
"could not initialize Py%sArrType_Type", \
#child); \
return -1; \
}
// 初始化单一继承关系的各个类型对象
if (PyType_Ready(&PyGenericArrType_Type) < 0) {
return -1;
}
SINGLE_INHERIT(Number, Generic);
SINGLE_INHERIT(Integer, Number);
SINGLE_INHERIT(Inexact, Number);
SINGLE_INHERIT(SignedInteger, Integer);
SINGLE_INHERIT(UnsignedInteger, Integer);
SINGLE_INHERIT(Floating, Inexact);
SINGLE_INHERIT(ComplexFloating, Inexact);
SINGLE_INHERIT(Flexible, Generic);
SINGLE_INHERIT(Character, Flexible);
#define DUAL_INHERIT(child, parent1, parent2) \
// 设置双重继承关系宏,初始化子类的类型对象
Py##child##ArrType_Type.tp_base = &Py##parent2##ArrType_Type; \
Py##child##ArrType_Type.tp_bases = \
Py_BuildValue("(OO)", &Py##parent2##ArrType_Type, \
&Py##parent1##_Type); \
Py##child##ArrType_Type.tp_hash = Py##parent1##_Type.tp_hash; \
if (PyType_Ready(&Py##child##ArrType_Type) < 0) { \
PyErr_Print(); \
PyErr_Format(PyExc_SystemError, \
"could not initialize Py%sArrType_Type", \
#child); \
return -1; \
}
#define DUAL_INHERIT2(child, parent1, parent2) \
// 设置另一种双重继承关系宏,将子类的类型对象基类设置为 parent1
Py##child##ArrType_Type.tp_base = &Py##parent1##_Type; \
Py##child##ArrType_Type = PyType_Type;
// 将 Py##child##ArrType_Type 设置为 PyType_Type
Py##child##ArrType_Type.tp_bases = \
Py_BuildValue("(OO)", &Py##parent1##_Type, \
&Py##parent2##ArrType_Type); \
// 设置 Py##child##ArrType_Type 的基类为 Py##parent1##_Type 和 Py##parent2##ArrType_Type
Py##child##ArrType_Type.tp_richcompare = \
Py##parent1##_Type.tp_richcompare;
// 设置 Py##child##ArrType_Type 的富比较方法为 Py##parent1##_Type 的富比较方法
Py##child##ArrType_Type.tp_hash = Py##parent1##_Type.tp_hash; \
// 设置 Py##child##ArrType_Type 的哈希方法为 Py##parent1##_Type 的哈希方法
if (PyType_Ready(&Py##child##ArrType_Type) < 0) { \
PyErr_Print(); \
PyErr_Format(PyExc_SystemError, \
"could not initialize Py%sArrType_Type", \
#child); \
return -1; \
}
// 如果初始化 Py##child##ArrType_Type 失败,则打印错误信息并返回 -1
SINGLE_INHERIT(Bool, Generic);
// 单继承:Bool 继承自 Generic
SINGLE_INHERIT(Byte, SignedInteger);
// 单继承:Byte 继承自 SignedInteger
SINGLE_INHERIT(Short, SignedInteger);
// 单继承:Short 继承自 SignedInteger
SINGLE_INHERIT(Int, SignedInteger);
// 单继承:Int 继承自 SignedInteger
SINGLE_INHERIT(Long, SignedInteger);
// 单继承:Long 继承自 SignedInteger
SINGLE_INHERIT(LongLong, SignedInteger);
// 单继承:LongLong 继承自 SignedInteger
/* Datetime doesn't fit in any category */
SINGLE_INHERIT(Datetime, Generic);
// 单继承:Datetime 继承自 Generic
/* Timedelta is an integer with an associated unit */
SINGLE_INHERIT(Timedelta, SignedInteger);
// 单继承:Timedelta 继承自 SignedInteger
SINGLE_INHERIT(UByte, UnsignedInteger);
// 单继承:UByte 继承自 UnsignedInteger
SINGLE_INHERIT(UShort, UnsignedInteger);
// 单继承:UShort 继承自 UnsignedInteger
SINGLE_INHERIT(UInt, UnsignedInteger);
// 单继承:UInt 继承自 UnsignedInteger
SINGLE_INHERIT(ULong, UnsignedInteger);
// 单继承:ULong 继承自 UnsignedInteger
SINGLE_INHERIT(ULongLong, UnsignedInteger);
// 单继承:ULongLong 继承自 UnsignedInteger
SINGLE_INHERIT(Half, Floating);
// 单继承:Half 继承自 Floating
SINGLE_INHERIT(Float, Floating);
// 单继承:Float 继承自 Floating
DUAL_INHERIT(Double, Float, Floating);
// 双继承:Double 同时继承自 Float 和 Floating
SINGLE_INHERIT(LongDouble, Floating);
// 单继承:LongDouble 继承自 Floating
SINGLE_INHERIT(CFloat, ComplexFloating);
// 单继承:CFloat 继承自 ComplexFloating
DUAL_INHERIT(CDouble, Complex, ComplexFloating);
// 双继承:CDouble 同时继承自 Complex 和 ComplexFloating
SINGLE_INHERIT(CLongDouble, ComplexFloating);
// 单继承:CLongDouble 继承自 ComplexFloating
DUAL_INHERIT2(String, String, Character);
// 双继承:String 同时继承自 String 和 Character
DUAL_INHERIT2(Unicode, Unicode, Character);
// 双继承:Unicode 同时继承自 Unicode 和 Character
SINGLE_INHERIT(Void, Flexible);
// 单继承:Void 继承自 Flexible
SINGLE_INHERIT(Object, Generic);
// 单继承:Object 继承自 Generic
return 0;
// 函数返回 0,表示初始化成功
/*
* Clean up string and unicode array types so they act more like
* strings -- get their tables from the standard types.
*/
}
/* place a flag dictionary in d */
static void
set_flaginfo(PyObject *d)
{
PyObject *s;
PyObject *newd;
newd = PyDict_New();
#define _addnew(key, val, one) \
PyDict_SetItemString(newd, #key, s=PyLong_FromLong(val)); \
Py_DECREF(s); \
PyDict_SetItemString(newd, #one, s=PyLong_FromLong(val)); \
Py_DECREF(s)
#define _addone(key, val) \
PyDict_SetItemString(newd, #key, s=PyLong_FromLong(val)); \
Py_DECREF(s)
/* Define flag constants and populate them in the dictionary */
_addnew(OWNDATA, NPY_ARRAY_OWNDATA, O);
_addnew(FORTRAN, NPY_ARRAY_F_CONTIGUOUS, F);
_addnew(CONTIGUOUS, NPY_ARRAY_C_CONTIGUOUS, C);
_addnew(ALIGNED, NPY_ARRAY_ALIGNED, A);
_addnew(WRITEBACKIFCOPY, NPY_ARRAY_WRITEBACKIFCOPY, X);
_addnew(WRITEABLE, NPY_ARRAY_WRITEABLE, W);
_addone(C_CONTIGUOUS, NPY_ARRAY_C_CONTIGUOUS);
_addone(F_CONTIGUOUS, NPY_ARRAY_F_CONTIGUOUS);
#undef _addone
#undef _addnew
/* Add the flag dictionary to the input dictionary `d` */
PyDict_SetItemString(d, "_flagdict", newd);
Py_DECREF(newd);
return;
}
// static variables are automatically zero-initialized
NPY_VISIBILITY_HIDDEN npy_thread_unsafe_state_struct npy_thread_unsafe_state;
static int
initialize_thread_unsafe_state(void) {
char *env = getenv("NUMPY_WARN_IF_NO_MEM_POLICY");
if ((env != NULL) && (strncmp(env, "1", 1) == 0)) {
npy_thread_unsafe_state.warn_if_no_mem_policy = 1;
}
else {
npy_thread_unsafe_state.warn_if_no_mem_policy = 0;
}
/* Initialize legacy print mode to INT_MAX */
npy_thread_unsafe_state.legacy_print_mode = INT_MAX;
return 0;
}
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
"_multiarray_umath",
NULL,
-1,
array_module_methods,
NULL,
NULL,
NULL,
NULL
};
/* Initialization function for the module */
PyMODINIT_FUNC PyInit__multiarray_umath(void) {
PyObject *m, *d, *s;
PyObject *c_api;
/* Create the module and add the functions */
m = PyModule_Create(&moduledef);
if (!m) {
return NULL;
}
/* Initialize CPU features */
if (npy_cpu_init() < 0) {
goto err;
}
/* Initialize CPU dispatch tracer */
if (npy_cpu_dispatch_tracer_init(m) < 0) {
goto err;
}
#if defined(MS_WIN64) && defined(__GNUC__)
PyErr_WarnEx(PyExc_Warning,
"Numpy built with MINGW-W64 on Windows 64 bits is experimental, " \
"and only available for \n" \
"testing. You are advised not to use it for production. \n\n" \
"CRASHES ARE TO BE EXPECTED - PLEASE REPORT THEM TO NUMPY DEVELOPERS",
1);
#endif
/* Initialize access to the PyDateTime API */
numpy_pydatetime_import();
if (PyErr_Occurred()) {
goto err;
/* 将一些符号常量添加到模块中 */
/* 获取模块的字典 */
d = PyModule_GetDict(m);
if (!d) {
goto err;
}
/* 初始化内部字符串 */
if (intern_strings() < 0) {
goto err;
}
/* 初始化静态全局变量 */
if (initialize_static_globals() < 0) {
goto err;
}
/* 初始化线程不安全状态 */
if (initialize_thread_unsafe_state() < 0) {
goto err;
}
/* 初始化扩展对象 */
if (init_extobj() < 0) {
goto err;
}
/* 准备PyUFunc_Type类型 */
if (PyType_Ready(&PyUFunc_Type) < 0) {
goto err;
}
/* 设置PyArrayDTypeMeta_Type的基类为PyType_Type,并准备该类型 */
PyArrayDTypeMeta_Type.tp_base = &PyType_Type;
if (PyType_Ready(&PyArrayDTypeMeta_Type) < 0) {
goto err;
}
/* 设置PyArrayDescr_Type的哈希函数为PyArray_DescrHash,并设置其类型为PyArrayDTypeMeta_Type,然后准备该类型 */
PyArrayDescr_Type.tp_hash = PyArray_DescrHash;
Py_SET_TYPE(&PyArrayDescr_Type, &PyArrayDTypeMeta_Type);
if (PyType_Ready(&PyArrayDescr_Type) < 0) {
goto err;
}
/* 初始化类型转换表 */
initialize_casting_tables();
/* 初始化数值类型 */
initialize_numeric_types();
/* 初始化标量数学函数 */
if (initscalarmath(m) < 0) {
goto err;
}
/* 准备PyArray_Type类型 */
if (PyType_Ready(&PyArray_Type) < 0) {
goto err;
}
/* 设置标量类型 */
if (setup_scalartypes(d) < 0) {
goto err;
}
/* 设置迭代器类型并准备 */
PyArrayIter_Type.tp_iter = PyObject_SelfIter;
if (PyType_Ready(&PyArrayIter_Type) < 0) {
goto err;
}
/* 准备PyArrayMapIter_Type类型 */
if (PyType_Ready(&PyArrayMapIter_Type) < 0) {
goto err;
}
/* 准备PyArrayMultiIter_Type类型 */
if (PyType_Ready(&PyArrayMultiIter_Type) < 0) {
goto err;
}
/* 设置PyArrayNeighborhoodIter_Type的构造函数为PyType_GenericNew,并准备该类型 */
PyArrayNeighborhoodIter_Type.tp_new = PyType_GenericNew;
if (PyType_Ready(&PyArrayNeighborhoodIter_Type) < 0) {
goto err;
}
/* 准备NpyIter_Type类型 */
if (PyType_Ready(&NpyIter_Type) < 0) {
goto err;
}
/* 准备PyArrayFlags_Type类型 */
if (PyType_Ready(&PyArrayFlags_Type) < 0) {
goto err;
}
/* 设置NpyBusDayCalendar_Type的构造函数为PyType_GenericNew,并准备该类型 */
NpyBusDayCalendar_Type.tp_new = PyType_GenericNew;
if (PyType_Ready(&NpyBusDayCalendar_Type) < 0) {
goto err;
}
/*
* PyExc_Exception应该捕获所有标准错误,而不是字符串异常"multiarray.error"
* 这是为了向后兼容现有代码
*/
/* 将PyExc_Exception设置为"error"键的值 */
PyDict_SetItemString(d, "error", PyExc_Exception);
/* 设置"tracemalloc_domain"键的值为NPY_TRACE_DOMAIN的长整型 */
s = PyLong_FromLong(NPY_TRACE_DOMAIN);
PyDict_SetItemString(d, "tracemalloc_domain", s);
Py_DECREF(s);
/* 设置"__version__"键的值为"3.1"的Unicode字符串 */
s = PyUnicode_FromString("3.1");
PyDict_SetItemString(d, "__version__", s);
Py_DECREF(s);
/* 获取CPU特性字典 */
s = npy_cpu_features_dict();
if (s == NULL) {
goto err;
}
/* 将CPU特性字典设置为"__cpu_features__"键的值 */
if (PyDict_SetItemString(d, "__cpu_features__", s) < 0) {
Py_DECREF(s);
goto err;
}
Py_DECREF(s);
/* 获取CPU基线列表 */
s = npy_cpu_baseline_list();
if (s == NULL) {
goto err;
}
/* 将CPU基线列表设置为"__cpu_baseline__"键的值 */
if (PyDict_SetItemString(d, "__cpu_baseline__", s) < 0) {
Py_DECREF(s);
goto err;
}
Py_DECREF(s);
/* 获取CPU分派列表 */
s = npy_cpu_dispatch_list();
if (s == NULL) {
goto err;
}
/* 将CPU分派列表设置为"__cpu_dispatch__"键的值 */
if (PyDict_SetItemString(d, "__cpu_dispatch__", s) < 0) {
Py_DECREF(s);
goto err;
}
Py_DECREF(s);
// 使用 PyCapsule_New 函数创建一个包含 _datetime_strings 的指针的 PyCapsule 对象,并赋值给变量 s
s = PyCapsule_New((void *)_datetime_strings, NULL, NULL);
// 检查 s 是否为空,如果为空则跳转到 err 标签处理错误
if (s == NULL) {
goto err;
}
// 将 PyCapsule 对象 s 以 "DATETIMEUNITS" 为键添加到字典 d 中
PyDict_SetItemString(d, "DATETIMEUNITS", s);
// 减少 PyCapsule 对象 s 的引用计数,释放其占用的资源
Py_DECREF(s);
#define ADDCONST(NAME) \
s = PyLong_FromLong(NPY_##NAME); \
PyDict_SetItemString(d, #NAME, s); \
Py_DECREF(s)
// 添加常量 ALLOW_THREADS 到字典 d 中
ADDCONST(ALLOW_THREADS);
// 添加常量 BUFSIZE 到字典 d 中
ADDCONST(BUFSIZE);
// 添加常量 CLIP 到字典 d 中
ADDCONST(CLIP);
// 添加常量 ITEM_HASOBJECT 到字典 d 中
ADDCONST(ITEM_HASOBJECT);
// 添加常量 LIST_PICKLE 到字典 d 中
ADDCONST(ITEM_IS_POINTER);
// 添加常量 NEEDS_INIT 到字典 d 中
ADDCONST(NEEDS_INIT);
// 添加常量 NEEDS_PYAPI 到字典 d 中
ADDCONST(NEEDS_PYAPI);
// 添加常量 USE_GETITEM 到字典 d 中
ADDCONST(USE_GETITEM);
// 添加常量 USE_SETITEM 到字典 d 中
ADDCONST(USE_SETITEM);
// 添加常量 RAISE 到字典 d 中
ADDCONST(RAISE);
// 添加常量 WRAP 到字典 d 中
ADDCONST(WRAP);
// 添加常量 MAXDIMS 到字典 d 中
ADDCONST(MAXDIMS);
// 添加常量 MAY_SHARE_BOUNDS 到字典 d 中
ADDCONST(MAY_SHARE_BOUNDS);
// 添加常量 MAY_SHARE_EXACT 到字典 d 中
ADDCONST(MAY_SHARE_EXACT);
#undef ADDCONST
// 将 ndarray 类型的对象添加到字典 d 中
PyDict_SetItemString(d, "ndarray", (PyObject *)&PyArray_Type);
// 将 flatiter 类型的对象添加到字典 d 中
PyDict_SetItemString(d, "flatiter", (PyObject *)&PyArrayIter_Type);
// 将 nditer 类型的对象添加到字典 d 中
PyDict_SetItemString(d, "nditer", (PyObject *)&NpyIter_Type);
// 将 broadcast 类型的对象添加到字典 d 中
PyDict_SetItemString(d, "broadcast",
(PyObject *)&PyArrayMultiIter_Type);
// 将 dtype 类型的对象添加到字典 d 中
PyDict_SetItemString(d, "dtype", (PyObject *)&PyArrayDescr_Type);
// 将 flagsobj 类型的对象添加到字典 d 中
PyDict_SetItemString(d, "flagsobj", (PyObject *)&PyArrayFlags_Type);
// 将 busdaycalendar 类型的对象添加到字典 d 中
/* Business day calendar object */
PyDict_SetItemString(d, "busdaycalendar",
(PyObject *)&NpyBusDayCalendar_Type);
// 设置标志信息
set_flaginfo(d);
// 完成标量类型的初始化并通过命名空间或 typeinfo 字典公开它们
// 如果设置类型信息失败,则跳转到 err 标签
if (set_typeinfo(d) != 0) {
goto err;
}
// 准备 PyArrayFunctionDispatcher_Type 类型,若失败则跳转到 err 标签
if (PyType_Ready(&PyArrayFunctionDispatcher_Type) < 0) {
goto err;
}
// 将 PyArrayFunctionDispatcher_Type 类型添加到字典 d 中
PyDict_SetItemString(
d, "_ArrayFunctionDispatcher",
(PyObject *)&PyArrayFunctionDispatcher_Type);
// 准备 PyArrayArrayConverter_Type 类型,若失败则跳转到 err 标签
if (PyType_Ready(&PyArrayArrayConverter_Type) < 0) {
goto err;
}
// 将 PyArrayArrayConverter_Type 类型添加到字典 d 中
PyDict_SetItemString(
d, "_array_converter",
(PyObject *)&PyArrayArrayConverter_Type);
// 准备 PyArrayMethod_Type 类型,若失败则跳转到 err 标签
if (PyType_Ready(&PyArrayMethod_Type) < 0) {
goto err;
}
// 准备 PyBoundArrayMethod_Type 类型,若失败则跳转到 err 标签
if (PyType_Ready(&PyBoundArrayMethod_Type) < 0) {
goto err;
}
// 初始化并映射 Python 类型到 dtype,若失败则跳转到 err 标签
if (initialize_and_map_pytypes_to_dtypes() < 0) {
goto err;
}
// 初始化类型转换
if (PyArray_InitializeCasts() < 0) {
goto err;
}
// 初始化字符串 dtype,若失败则跳转到 err 标签
if (init_string_dtype() < 0) {
goto err;
}
// 初始化 umath 模块,若失败则跳转到 err 标签
if (initumath(m) != 0) {
goto err;
}
// 设置矩阵乘法标志,若失败则跳转到 err 标签
if (set_matmul_flags(d) < 0) {
goto err;
}
// 初始化静态引用到 ndarray.__array_*__ 特殊方法
npy_static_pydata.ndarray_array_finalize = PyObject_GetAttrString(
(PyObject *)&PyArray_Type, "__array_finalize__");
// 若获取 ndarray_array_finalize 失败,则跳转到 err 标签
if (npy_static_pydata.ndarray_array_finalize == NULL) {
goto err;
}
npy_static_pydata.ndarray_array_ufunc = PyObject_GetAttrString(
(PyObject *)&PyArray_Type, "__array_ufunc__");
// 若获取 ndarray_array_ufunc 失败,则跳转到 err 标签
if (npy_static_pydata.ndarray_array_ufunc == NULL) {
goto err;
}
npy_static_pydata.ndarray_array_function = PyObject_GetAttrString(
(PyObject *)&PyArray_Type, "__array_function__");
// 若获取 ndarray_array_function 失败,则跳转到 err 标签
if (npy_static_pydata.ndarray_array_function == NULL) {
goto err;
}
/*
* 初始化 np.dtypes.StringDType
*
* 注意,这里在初始化旧版内置 DTypes 之后进行,
* 以避免在 NumPy 设置期间出现循环依赖。
* 这是因为需要在 init_string_dtype() 之后执行此操作,
* 而 init_string_dtype() 需要在旧版 dtypemeta 类可用之后执行。
*/
npy_cache_import("numpy.dtypes", "_add_dtype_helper",
&npy_thread_unsafe_state._add_dtype_helper);
if (npy_thread_unsafe_state._add_dtype_helper == NULL) {
goto err;
}
if (PyObject_CallFunction(
npy_thread_unsafe_state._add_dtype_helper,
"Os", (PyObject *)&PyArray_StringDType, NULL) == NULL) {
goto err;
}
PyDict_SetItemString(d, "StringDType", (PyObject *)&PyArray_StringDType);
/*
* 初始化默认的 PyDataMem_Handler capsule 单例。
*/
PyDataMem_DefaultHandler = PyCapsule_New(
&default_handler, MEM_HANDLER_CAPSULE_NAME, NULL);
if (PyDataMem_DefaultHandler == NULL) {
goto err;
}
/*
* 使用默认的 PyDataMem_Handler capsule 初始化上下文本地的当前 handler。
*/
current_handler = PyContextVar_New("current_allocator", PyDataMem_DefaultHandler);
if (current_handler == NULL) {
goto err;
}
// 初始化静态引用的零类似数组
npy_static_pydata.zero_pyint_like_arr = PyArray_ZEROS(
0, NULL, NPY_LONG, NPY_FALSE);
if (npy_static_pydata.zero_pyint_like_arr == NULL) {
goto err;
}
((PyArrayObject_fields *)npy_static_pydata.zero_pyint_like_arr)->flags |=
(NPY_ARRAY_WAS_PYTHON_INT|NPY_ARRAY_WAS_INT_AND_REPLACED);
if (verify_static_structs_initialized() < 0) {
goto err;
}
/*
* 导出 API 表
*/
c_api = PyCapsule_New((void *)PyArray_API, NULL, NULL);
/* dtype API 不是通过 Python 脚本自动填充/生成的: */
_fill_dtype_api(PyArray_API);
if (c_api == NULL) {
goto err;
}
PyDict_SetItemString(d, "_ARRAY_API", c_api);
Py_DECREF(c_api);
c_api = PyCapsule_New((void *)PyUFunc_API, NULL, NULL);
if (c_api == NULL) {
goto err;
}
PyDict_SetItemString(d, "_UFUNC_API", c_api);
Py_DECREF(c_api);
if (PyErr_Occurred()) {
goto err;
}
return m;
err:
if (!PyErr_Occurred()) {
PyErr_SetString(PyExc_RuntimeError,
"cannot load multiarray module.");
}
Py_DECREF(m);
return NULL;
}
# 这行代码是一个单独的右大括号 '}',用于结束一个代码块或语句块。
# 在程序中,右大括号通常与左大括号 '{' 成对出现,用于定义代码块的起始和结束位置。
# 在这段示例中,单独的右大括号可能是某个控制结构、函数定义或类定义的结束标志,但缺少上下文难以具体确定其用途。
# 一般情况下,右大括号用于结束代码块,但单独的右大括号出现在示例中,需要更多上下文才能准确解释其作用。