数组 API#

一个第一流智力的考验是能够在同一时间
心中持有两个对立的想法,并且仍然能够保持
运作的能力。
F. Scott Fitzgerald
对于一项成功的技术,现实必须优先于公众
关系,因为大自然是无法被欺骗的。
Richard P. Feynman

数组结构和数据访问#

这些宏访问 ndarraytypes.h 中定义的 PyArrayObject 结构体成员。输入参数 arr 可以是任何可以直接解释为 PyArrayObject*PyObject* (任何 PyArray_Type 及其子类型的实例)。

int PyArray_NDIM(PyArrayObject *arr)#

数组的维度数。

int PyArray_FLAGS(PyArrayObject *arr)#

返回一个表示 数组标志 的整数。

int PyArray_TYPE(PyArrayObject *arr)#

返回此数组元素的(内置)类型编号。

int PyArray_Pack(const PyArray_Descr *descr, void *item, const PyObject *value)#

新增于版本 2.0。

将数据类型为 descr 的内存位置 item 设置为 value

该函数等同于使用 Python 赋值设置单个数组元素。成功时返回 0,失败时返回 -1 并设置错误。

注意

如果 descr 设置了 NPY_NEEDS_INIT 标志,则数据必须有效或内存必须为零。

int PyArray_SETITEM(PyArrayObject *arr, void *itemptr, PyObject *obj)#

obj 转换为 ndarray arr 并将其放置在 itemptr 指向的位置。如果发生错误,则返回 -1,成功则返回 0。

注意

通常,在处理任意 Python 对象时,更倾向于使用 PyArray_Pack。例如,Setitem 无法处理不同 dtype 之间的任意类型转换。

void PyArray_ENABLEFLAGS(PyArrayObject *arr, int flags)#

启用指定的数组标志。此函数不进行验证,并假定您知道自己在做什么。

void PyArray_CLEARFLAGS(PyArrayObject *arr, int flags)#

清除指定的数组标志。此函数不进行验证,并假定您知道自己在做什么。

void *PyArray_DATA(PyArrayObject *arr)#
char *PyArray_BYTES(PyArrayObject *arr)#

这两个宏类似,用于获取数组数据缓冲区的指针。第一个宏可以(也应该)分配给一个指向数据缓冲区的特定指针,而第二个宏用于通用处理。如果您没有保证数组是连续的/对齐的,请务必了解如何访问数组数据以避免内存和/或对齐问题。

npy_intp *PyArray_DIMS(PyArrayObject *arr)#

返回指向数组维度/形状的指针。元素的数量与数组的维度数匹配。对于 0 维数组,可以返回 NULL

npy_intp *PyArray_SHAPE(PyArrayObject *arr)#

PyArray_DIMS 的同义词,命名以便与 Python 中使用的 shape 一致。

npy_intp *PyArray_STRIDES(PyArrayObject *arr)#

返回指向数组步幅的指针。元素的数量与数组的维度数匹配。

npy_intp PyArray_DIM(PyArrayObject *arr, int n)#

返回第 n 个维度上的形状。

npy_intp PyArray_STRIDE(PyArrayObject *arr, int n)#

返回第 n 个维度上的步幅。

npy_intp PyArray_ITEMSIZE(PyArrayObject *arr)#

返回此数组元素的项大小。

请注意,在 1.7 版本中已弃用的旧 API 中,此函数的返回类型为 int

npy_intp PyArray_SIZE(PyArrayObject *arr)#

返回数组的总大小(以元素数量计)。

npy_intp PyArray_Size(PyObject *obj)#

如果 obj 不是 ndarray 的子类,则返回 0。否则,返回数组中的总元素数。比 PyArray_SIZE (obj) 更安全的版本。

npy_intp PyArray_NBYTES(PyArrayObject *arr)#

返回数组消耗的总字节数。

PyObject *PyArray_BASE(PyArrayObject *arr)#

此函数返回数组的基对象。在大多数情况下,这意味着拥有数组指向的内存的对象。

如果您使用 C API 构建数组并指定自己的内存,则应使用函数 PyArray_SetBaseObject 将基设置为拥有内存的对象。

如果设置了 NPY_ARRAY_WRITEBACKIFCOPY 标志,则其含义不同,即基是将在复制解析时复制到其中的数组。基属性的这种两种功能重载很可能会在 NumPy 的未来版本中更改。

PyArray_Descr *PyArray_DESCR(PyArrayObject *arr)#

返回对数组 dtype 属性的借用引用。

PyArray_Descr *PyArray_DTYPE(PyArrayObject *arr)#

PyArray_DESCR 的同义词,命名以便与 Python 中的 ‘dtype’ 使用一致。

PyObject *PyArray_GETITEM(PyArrayObject *arr, void *itemptr)#

从 ndarray arritemptr 指向的位置获取一个内置类型的 Python 对象。失败时返回 NULL

numpy.ndarray.item 与 PyArray_GETITEM 相同。

int PyArray_FinalizeFunc(PyArrayObject *arr, PyObject *obj)#

由 `__array_finalize__` 胶囊 PyCapsule 指向的函数。第一个参数是新创建的子类型。第二个参数(如果不是 NULL)是“父”数组(如果数组是通过切片或其他明显存在父项的操作创建的)。此例程可以执行任何它想要的操作。它应在错误时返回 -1,否则返回 0。

数据访问#

这些函数和宏提供了从 C 轻松访问 ndarray 元素的途径。这些适用于所有数组。但是,如果数组不是机器字节序、未对齐或不可写,您可能需要小心访问数组数据。换句话说,除非您知道自己在做什么,或者之前已使用 PyArray_FromAny 保证了数组是可写、对齐且为机器字节序的,否则请务必尊重标志的状态。如果您希望处理所有类型的数组,则每种类型的 copyswap 函数对于处理不符合要求的数组非常有用。某些平台(例如 Solaris)不喜欢未对齐的数据,并且在解引用未对齐指针时会崩溃。其他平台(例如 x86 Linux)在处理未对齐数据时会稍慢。

void *PyArray_GetPtr(PyArrayObject *aobj, npy_intp *ind)#

返回 ndarray aobj 在由 c 数组 ind(其大小必须至少为 aobj ->nd)给出的 N 维索引处的数据指针。您可能需要将返回的指针转换为 ndarray 的数据类型。

void *PyArray_GETPTR1(PyArrayObject *obj, npy_intp i)#
void *PyArray_GETPTR2(PyArrayObject *obj, npy_intp i, npy_intp j)#
void *PyArray_GETPTR3(PyArrayObject *obj, npy_intp i, npy_intp j, npy_intp k)#
void *PyArray_GETPTR4(PyArrayObject *obj, npy_intp i, npy_intp j, npy_intp k, npy_intp l)#

快速、内联地访问 ndarray obj 中给定坐标处的元素,该 ndarray 必须分别具有 1、2、3 或 4 个维度(不进行检查)。相应的 ijkl 坐标可以是任何整数,但将被解释为 npy_intp。您可能需要将返回的指针转换为 ndarray 的数据类型。

创建数组#

从头开始#

PyObject *PyArray_NewFromDescr(PyTypeObject *subtype, PyArray_Descr *descr, int nd, npy_intp const *dims, npy_intp const *strides, void *data, int flags, PyObject *obj)#

此函数会窃取 descr 的引用。获取它的最简单方法是使用 PyArray_DescrFromType

这是主要的数组创建函数。大多数新数组都是使用这个灵活的函数创建的。

返回的对象是 Python 类型 subtype 的对象,它必须是 PyArray_Type 的子类型。数组有 nd 个维度,由 dims 描述。新数组的数据类型描述符是 descr

如果 subtype 是数组子类的类型而不是基础 &PyArray_Type,则 obj 是传递给子类 `__array_finalize__` 方法的对象。

如果 dataNULL,则将分配新的未初始化内存,flags 可以为非零以指示 Fortran 风格的连续数组。使用 PyArray_FILLWBYTE 初始化内存。

如果 data 不是 NULL,那么它被假定指向用于数组的内存,并且 flags 参数被用作数组的新标志(除了 NPY_ARRAY_OWNDATA 的状态,新数组的 NPY_ARRAY_WRITEBACKIFCOPY 标志将被重置)。

此外,如果 data 非 NULL,则还可以提供 strides。如果 stridesNULL,则数组跨度被计算为 C 风格连续(默认)或 Fortran 风格连续(对于 data = NULLflags 为非零,或者对于非 NULL dataflags & NPY_ARRAY_F_CONTIGUOUS 非零)。任何提供的 dimsstrides 都将被复制到新数组对象新分配的维度和跨度数组中。

PyArray_CheckStrides 可以帮助验证非 NULL 的跨度信息。

如果提供了 data,它必须在数组的生命周期内保持有效。管理此的一种方法是通过 PyArray_SetBaseObject

PyObject *PyArray_NewLikeArray(PyArrayObject *prototype, NPY_ORDER order, PyArray_Descr *descr, int subok)#

此函数会窃取 descr 的引用(如果它不是 NULL)。此数组创建例程允许方便地创建与现有数组的形状和内存布局匹配的新数组,可能会更改布局和/或数据类型。

orderNPY_ANYORDER 时,如果 prototype 是 Fortran 数组,则结果顺序为 NPY_FORTRANORDER,否则为 NPY_CORDER。当 orderNPY_KEEPORDER 时,结果顺序与 prototype 匹配,即使 prototype 的轴不是 C 或 Fortran 顺序。

如果 descr 为 NULL,则使用 prototype 的数据类型。

如果 subok 为 1,则新创建的数组将使用 prototype 的子类型来创建新数组,否则它将创建一个基类数组。

PyObject *PyArray_New(PyTypeObject *subtype, int nd, npy_intp const *dims, int type_num, npy_intp const *strides, void *data, int itemsize, int flags, PyObject *obj)#

这类似于 PyArray_NewFromDescr(…) ,只不过您使用 type_numitemsize 来指定数据类型描述符,其中 type_num 对应于内置(或用户定义的)类型。如果类型总是具有相同的字节数,则忽略 itemsize。否则,itemsize 指定此数组的特定大小。

警告

如果将 data 传递给 PyArray_NewFromDescrPyArray_New,则此内存必须在删除新数组之前保持有效。如果此数据来自另一个引用计数的 Python 对象,则可以通过在该对象上调用 Py_INCREF 并将新数组的 base 成员设置为指向该对象来完成此操作。这将确保在返回的数组存在期间不会释放提供的内存。如果传入了跨度,则它们必须与数组的维度、itemsize 和 data 一致。

PyObject *PyArray_SimpleNew(int nd, npy_intp const *dims, int typenum)#

创建一个新的未初始化数组,其类型为 typenum,在 nd 维中的每个维度的大小由整数数组 dims 给出。数组的内存是未初始化的(除非 typenum 是 NPY_OBJECT,在这种情况下,数组中的每个元素都设置为 NULL)。typenum 参数允许指定任何内置数据类型,例如 NPY_FLOATNPY_LONG。可以使用 PyArray_FILLWBYTE(return_object, 0) 将数组内存设置为零。此函数不能用于创建灵活类型数组(未提供 itemsize)。

PyObject *PyArray_SimpleNewFromData(int nd, npy_intp const *dims, int typenum, void *data)#

创建围绕由给定指针指向的 data 的数组包装器。数组标志将具有默认值,即数据区域是良好的且是 C 风格连续的。数组的形状由长度为 nddims C 数组给出。数组的数据类型由 typenum 指示。如果 data 来自另一个引用计数的 Python 对象,则应在传入指针后增加该对象的引用计数,并将返回的 ndarray 的 base 成员指向拥有该数据的 Python 对象。这将确保在返回的数组存在期间不会释放提供的内存。

PyObject *PyArray_SimpleNewFromDescr(int nd, npy_int const *dims, PyArray_Descr *descr)#

此函数会窃取 descr 的引用。

使用提供的数据类型描述符 descr 创建一个新数组,其形状由 nddims 确定。

void PyArray_FILLWBYTE(PyObject *obj, int val)#

val(求值为字节)的内容填充由 obj 指向的数组(它必须是 ndarray 的子类)。此宏调用 memset,因此 obj 必须是连续的。

PyObject *PyArray_Zeros(int nd, npy_intp const *dims, PyArray_Descr *dtype, int fortran)#

构建一个具有由 dims 给出的形状和由 dtype 给出的数据类型的新 nd 维数组。如果 fortran 非零,则创建一个 Fortran 顺序数组,否则创建一个 C 顺序数组。内存将被零填充(如果 dtype 对应于 NPY_OBJECT,则填充为 0 对象)。

PyObject *PyArray_ZEROS(int nd, npy_intp const *dims, int type_num, int fortran)#

这是 PyArray_Zeros 的宏形式,它接受一个类型编号而不是数据类型对象。

PyObject *PyArray_Empty(int nd, npy_intp const *dims, PyArray_Descr *dtype, int fortran)#

构建一个具有由 dims 给出的形状和由 dtype 给出的数据类型的新 nd 维数组。如果 fortran 非零,则创建一个 Fortran 顺序数组,否则创建一个 C 顺序数组。数组是未初始化的,除非数据类型对应于 NPY_OBJECT,在这种情况下,数组将填充为 Py_None

PyObject *PyArray_EMPTY(int nd, npy_intp const *dims, int typenum, int fortran)#

这是 PyArray_Empty 的宏形式,它接受一个类型编号 typenum 而不是数据类型对象。

PyObject *PyArray_Arange(double start, double stop, double step, int typenum)#

构建一个数据类型为 typenum 的新一维数组,该数组从 startstop(不包含)以 step 的增量进行范围。等效于 **arange** (start, stop, step, dtype)。

PyObject *PyArray_ArangeObj(PyObject *start, PyObject *stop, PyObject *step, PyArray_Descr *descr)#

构建一个由 descr 确定数据类型的一维数组,该数组从 startstop(不包含)以 step 的增量进行范围。等效于 arange( start, stop, step, typenum )。

int PyArray_SetBaseObject(PyArrayObject *arr, PyObject *obj)#

此函数 **窃取** obj 的 **引用** 并将其设置为 arr 的 base 属性。

如果您通过将自己的内存缓冲区作为参数来构造数组,则需要设置数组的 base 属性,以确保内存缓冲区的生存期适当。

返回值:成功时为 0,失败时为 -1。

如果提供的对象是一个数组,此函数将遍历 base 指针链,以便每个数组直接指向内存的所有者。一旦设置了 base,就不能将其更改为其他值。

来自其他对象#

PyObject *PyArray_FromAny(PyObject *op, PyArray_Descr *dtype, int min_depth, int max_depth, int requirements, PyObject *context)#

这是从任何嵌套序列、公开数组接口的对象 op 获取数组的主要函数。参数允许指定所需的 dtype、可接受的最小 (min_depth) 和最大 (max_depth) 维度数,以及数组的其他 requirements。此函数 **窃取 dtype 参数的引用**,该参数需要是一个 PyArray_Descr 结构,指示所需的数据类型(包括所需的字节序)。dtype 参数可以为 NULL,表示可以接受任何数据类型(和字节序)。除非 NPY_ARRAY_FORCECAST 存在于 flags 中,否则,如果无法从对象安全地获取数据类型,此调用将生成错误。如果您想对 dtype 使用 NULL 并确保数组不被交换,请使用 PyArray_CheckFromAny。深度参数中的任何一个值为 0 都会导致该参数被忽略。以下任何数组标志都可以添加(例如,使用 |)来获取 requirements 参数。如果您的代码可以处理通用(例如,跨步、字节交换或未对齐的数组),则 requirements 可以为 0。此外,如果 op 已经是数组(或公开数组接口),则会创建一个新数组(并使用序列协议从 op 填充)。新数组将具有 NPY_ARRAY_DEFAULT 作为其 flags 成员。context 参数未使用。

NPY_ARRAY_C_CONTIGUOUS

确保返回的数组是 C 风格连续的

NPY_ARRAY_F_CONTIGUOUS

确保返回的数组是 Fortran 风格连续的。

NPY_ARRAY_ALIGNED

确保返回的数组在数据类型的边界上对齐。对齐的数组具有数据指针和每个跨度因子作为数据类型描述符对齐因子的倍数。

NPY_ARRAY_WRITEABLE

确保返回的数组可以被写入。

NPY_ARRAY_ENSURECOPY

确保复制 op。如果不存在此标志,则在可以避免的情况下不复制数据。

NPY_ARRAY_ENSUREARRAY

确保结果是基类 ndarray。默认情况下,如果 op 是 ndarray 的子类实例,则返回该相同子类的实例。如果设置了此标志,则将返回 ndarray 对象。

NPY_ARRAY_FORCECAST

即使无法安全地进行转换,也要强制转换为输出类型。没有此标志,仅当可以安全地进行数据转换时才会发生转换,否则会引发错误。

NPY_ARRAY_WRITEBACKIFCOPY

如果 op 已经是数组,但不满足要求,则会创建一个副本(该副本将满足要求)。如果存在此标志且必须创建副本(来自已是数组的对象),则返回的副本中会设置相应的 NPY_ARRAY_WRITEBACKIFCOPY 标志,并将 op 设置为只读。您必须确保调用 PyArray_ResolveWritebackIfCopy 将内容复制回 op,并且 op 数组将再次变为可写。如果 op 最初就不可写,或者它不是数组,则会引发错误。

还可以添加 数组标志的组合

PyObject *PyArray_CheckFromAny(PyObject *op, PyArray_Descr *dtype, int min_depth, int max_depth, int requirements, PyObject *context)#

PyArray_FromAny(…) 几乎相同,但 requirements 可以包含 NPY_ARRAY_NOTSWAPPED(覆盖 dtype 中的规范)和 NPY_ARRAY_ELEMENTSTRIDES,它表示数组应以跨度为元素大小的倍数的方式对齐。

PyObject *PyArray_FromArray(PyArrayObject *op, PyArray_Descr *newtype, int requirements)#

这是 PyArray_FromAny 的特殊情况,适用于 op 已经是数组但需要特定 newtype(包括字节序)或具有特定 requirements 的情况。

PyObject *PyArray_FromStructInterface(PyObject *op)#

从公开 __array_struct__ 属性并遵循数组接口协议的 Python 对象返回 ndarray 对象。如果对象不包含此属性,则返回对 Py_NotImplemented 的借用引用。

PyObject *PyArray_FromInterface(PyObject *op)#

从公开 __array_interface__ 属性并遵循数组接口协议的 Python 对象返回 ndarray 对象。如果对象不包含此属性,则返回对 Py_NotImplemented 的借用引用。

PyObject *PyArray_FromArrayAttr(PyObject *op, PyArray_Descr *dtype, PyObject *context)#

从公开 __array__ 方法的 Python 对象返回 ndarray 对象。第三方 __array__ 实现必须接受 dtypecopy 关键字参数。 context 未使用。

PyObject *PyArray_ContiguousFromAny(PyObject *op, int typenum, int min_depth, int max_depth)#

此函数返回一个(C 风格)连续且行为良好的数组,该数组来自任何嵌套序列或导出数组接口的对象 `op`,类型为指定的(非灵活)枚举类型 `typenum`,最小深度为 `min_depth`,最大深度为 `max_depth`。这等同于调用 PyArray_FromAny,并将 `requirements` 设置为 NPY_ARRAY_DEFAULT,并将类型参数的 `type_num` 成员设置为 `typenum`。

PyObject *PyArray_ContiguousFromObject(PyObject *op, int typenum, int min_depth, int max_depth)#

此函数返回一个行为良好的 C 风格连续数组,该数组来自任何嵌套序列或导出数组接口的对象。数组的最小维度数由 `min_depth` 指定,最大维度数由 `max_depth` 指定。这等同于调用 PyArray_FromAny,并将 `requirements` 设置为 NPY_ARRAY_DEFAULTNPY_ARRAY_ENSUREARRAY

PyObject *PyArray_FromObject(PyObject *op, int typenum, int min_depth, int max_depth)#

从任何嵌套序列或导出数组接口的对象 `op` 返回一个对齐且字节序为本地的数组,其类型由枚举类型 `typenum` 指定。数组的最小维度数由 `min_depth` 指定,最大维度数由 `max_depth` 指定。这等同于调用 PyArray_FromAny,并将 `requirements` 设置为 `BEHAVED`。

PyObject *PyArray_EnsureArray(PyObject *op)#

此函数**获取 `op` 的引用**,并确保 `op` 是一个基类 ndarray。它特殊处理数组标量,否则调用 PyArray_FromAny ( `op`, NULL, 0, 0, NPY_ARRAY_ENSUREARRAY, NULL)。

PyObject *PyArray_FromString(char *string, npy_intp slen, PyArray_Descr *dtype, npy_intp num, char *sep)#

从长度为 `slen` 的二进制或(ASCII)文本字符串 `string` 构建一个单类型的一维 ndarray。要创建的数组的数据类型由 `dtype` 指定。如果 `num` 为 -1,则复制整个字符串并返回适当大小的数组,否则 `num` 是要从字符串中**复制**的项数。如果 `sep` 为 NULL(或 ""),则将字符串解释为二进制数据字节,否则将由 `sep` 分隔的子字符串转换为数据类型为 `dtype` 的项。某些数据类型在文本模式下可能不可读,如果发生这种情况,将引发错误。所有错误都返回 NULL。

PyObject *PyArray_FromFile(FILE *fp, PyArray_Descr *dtype, npy_intp num, char *sep)#

从二进制或文本文件中构造一个单类型的一维 ndarray。打开的文件指针为 `fp`,要创建的数组的数据类型由 `dtype` 指定。这必须与文件中的数据匹配。如果 `num` 为 -1,则读取直到文件末尾并返回适当大小的数组,否则 `num` 是要读取的项数。如果 `sep` 为 NULL(或 ""),则以二进制模式从文件读取,否则以文本模式从文件读取,其中 `sep` 提供项分隔符。某些数组类型在文本模式下可能无法读取,在这种情况下将引发错误。

PyObject *PyArray_FromBuffer(PyObject *buf, PyArray_Descr *dtype, npy_intp count, npy_intp offset)#

从导出(单段)缓冲区协议的对象 `buf`(或具有返回导出缓冲区协议的对象 `__buffer__` 属性的对象)构造一个单类型的一维 ndarray。将首先尝试可写缓冲区,然后是只读缓冲区。返回的数组的 `NPY_ARRAY_WRITEABLE` 标志将反映哪个成功了。数据假定从对象的内存位置开始偏移 `offset` 字节。缓冲区中数据的类型将根据数据类型描述符 `dtype` 进行解释。如果 `count` 为负,则将根据缓冲区大小和请求的项大小确定,否则 `count` 表示应从缓冲区转换多少个元素。

int PyArray_CopyInto(PyArrayObject *dest, PyArrayObject *src)#

将数据从源数组 `src` 复制到目标数组 `dest`,如果需要,执行数据类型转换。如果发生错误,则返回 -1(否则返回 0)。`src` 的形状必须可广播到 `dest` 的形状。NumPy 会检查复制两个数组时重叠的内存。

int PyArray_CopyObject(PyArrayObject *dest, PyObject *src)#

根据数组强制转换规则,将对象 `src` 分配给 NumPy 数组 `dest`。这基本上与 PyArray_FromAny 相同,但直接分配给输出数组。成功时返回 0,失败时返回 -1。

PyArrayObject *PyArray_GETCONTIGUOUS(PyObject *op)#

如果 `op` 已经是(C 风格)连续且行为良好的,则仅返回其引用,否则返回数组的(连续且行为良好的)副本。参数 `op` 必须是 ndarray(或其子类),并且不会对其进行检查。

PyObject *PyArray_FROM_O(PyObject *obj)#

将 `obj` 转换为 ndarray。参数可以是任何嵌套序列或导出数组接口的对象。这是 `PyArray_FromAny` 的宏形式,使用 `NULL`、0、0、0 作为其他参数。要使用此宏,您的代码必须能够处理任何数据类型描述符和任何数据标志组合。

PyObject *PyArray_FROM_OF(PyObject *obj, int requirements)#

与 `PyArray_FROM_O` 类似,但可以接受一个 `requirements` 参数,该参数指示结果数组必须具有的属性。可强制执行的要求包括 `NPY_ARRAY_C_CONTIGUOUS`、`NPY_ARRAY_F_CONTIGUOUS`、`NPY_ARRAY_ALIGNED`、`NPY_ARRAY_WRITEABLE`、`NPY_ARRAY_NOTSWAPPED`、`NPY_ARRAY_ENSURECOPY`、`NPY_ARRAY_WRITEBACKIFCOPY`、`NPY_ARRAY_FORCECAST` 和 `NPY_ARRAY_ENSUREARRAY`。也可以使用标志的标准组合。

PyObject *PyArray_FROM_OT(PyObject *obj, int typenum)#

与 `PyArray_FROM_O` 类似,但可以接受一个 `typenum` 参数,用于指定返回数组的类型编号。

PyObject *PyArray_FROM_OTF(PyObject *obj, int typenum, int requirements)#

`PyArray_FROM_OF` 和 `PyArray_FROM_OT` 的组合,允许提供 `typenum` 和 `flags` 参数。

PyObject *PyArray_FROMANY(PyObject *obj, int typenum, int min, int max, int requirements)#

与 `PyArray_FromAny` 类似,但数据类型使用类型编号指定。`PyArray_DescrFromType(typenum)` 直接传递给 `PyArray_FromAny`。此宏还将 `NPY_ARRAY_DEFAULT` 添加到 `requirements` 中,如果 `NPY_ARRAY_ENSURECOPY` 作为 `requirements` 传递。

PyObject *PyArray_CheckAxis(PyObject *obj, int *axis, int requirements)#

封装接受 `axis=` 关键字且能正确处理 `None` 作为 `axis` 参数的函数和方法的逻辑。输入数组为 `obj`,`*axis` 是一个转换后的整数(因此 `*axis == NPY_RAVEL_AXIS` 是 None 值),`requirements` 给出了 `obj` 所需的属性。输出是输入的转换版本,以满足要求,并且在需要时已进行展平。输出时,`*axis` 的负值将被转换,新值将得到检查以确保与 `obj` 的形状一致。

处理类型#

通用 Python 类型检查#

int PyArray_Check(PyObject *op)#

当 `op` 是 `PyArray_Type` 的子类型时,此表达式为真。

int PyArray_CheckExact(PyObject *op)#

当 `op` 的类型为 `PyArray_Type` 时,此表达式为真。

int PyArray_HasArrayInterface(PyObject *op, PyObject *out)#

如果 `op` 实现数组接口的任何部分,则 `out` 将包含一个指向使用该接口创建的新 ndarray 的新引用,或者如果转换过程中发生错误,`out` 将包含 `NULL`。否则,`out` 将包含对 `Py_NotImplemented` 的借用引用,并且不会设置错误条件。

int PyArray_HasArrayInterfaceType(PyObject *op, PyArray_Descr *dtype, PyObject *context, PyObject *out)#

如果 `op` 实现数组接口的任何部分,则 `out` 将包含一个指向使用该接口创建的新 ndarray 的新引用,或者如果转换过程中发生错误,`out` 将包含 `NULL`。否则,`out` 将包含对 `Py_NotImplemented` 的借用引用,并且不会设置错误条件。此版本允许在查找 `__array__` 属性的数组接口部分设置 dtype。`context` 未使用。

int PyArray_IsZeroDim(PyObject *op)#

当 `op` 是 `PyArray_Type`(或其子类)的实例且维度为 0 时,此表达式为真。

PyArray_IsScalar(op, cls)#

当 `op` 是 `Py{cls}ArrType_Type` 的实例时,此表达式为真。

int PyArray_CheckScalar(PyObject *op)#

当 `op` 是数组标量(`PyGenericArrType_Type` 的子类型的实例)或维度为 0 的 `PyArray_Type`(或其子类)的实例时,此表达式为真。

int PyArray_IsPythonNumber(PyObject *op)#

当 `op` 是内置数字类型(int、float、complex、long、bool)的实例时,此表达式为真。

int PyArray_IsPythonScalar(PyObject *op)#

当 `op` 是内置 Python 标量对象(int、float、complex、bytes、str、long、bool)的实例时,此表达式为真。

int PyArray_IsAnyScalar(PyObject *op)#

当 `op` 是 Python 标量对象(参见 `PyArray_IsPythonScalar`)或数组标量(`PyGenericArrType_Type` 的子类型的实例)时,此表达式为真。

int PyArray_CheckAnyScalar(PyObject *op)#

如果 op 是 Python 标量对象(参见 PyArray_IsPythonScalar)、数组标量(PyGenericArrType_Type 的子类型实例)或维度为 0 的 PyArray_Type 的子类型实例,则返回真。

数据类型访问器#

某些描述符属性可能并非始终定义,应或不能直接访问。

版本 2.0 中已更改: 在 NumPy 2.0 之前,ABI 不同,但对于用户 DTypes 而言不必要地庞大。这些访问器都已在 2.0 中添加,并且可以向后移植(参见 PyArray_Descr 结构已更改)。

npy_intp PyDataType_ELSIZE(PyArray_Descr *descr)#

数据类型的元素大小(Python 中的 itemsize)。

注意

如果 descr 附加到数组,则可以使用 PyArray_ITEMSIZE(arr),并且在所有 NumPy 版本中都可用。

void PyDataType_SET_ELSIZE(PyArray_Descr *descr, npy_intp size)#

允许设置元素大小,这仅与字符串/字节数据类型相关,因为这是定义具有新大小的字符串/字节数据类型的当前模式。

npy_intp PyDataType_ALIGNMENT(PyArray_Descr *descr)#

数据类型的对齐方式。

PyObject *PyDataType_METADATA(PyArray_Descr *descr)#

附加到 dtype 的元数据,可以是 NULL 或字典。

PyObject *PyDataType_NAMES(PyArray_Descr *descr)#

NULL 或附加到 dtype 的结构化字段名称的元组。

PyObject *PyDataType_FIELDS(PyArray_Descr *descr)#

NULLNone 或结构化 dtype 字段的字典。此字典不应被修改。NumPy 可能会在未来更改存储字段的方式。

这与 np.dtype.fields 返回的字典相同。

NpyAuxData *PyDataType_C_METADATA(PyArray_Descr *descr)#

附加到描述符的 C-元数据对象。通常不需要此访问器。C-元数据字段提供对日期/时间/时间间隔单位信息的访问。

PyArray_ArrayDescr *PyDataType_SUBARRAY(PyArray_Descr *descr)#

关于子数组 dtype 的信息,等同于 Python 的 np.dtype.basenp.dtype.shape

如果此值非 NULL,则此数据类型描述符是另一个数据类型描述符的 C 风格连续数组。换句话说,此描述符描述的每个元素实际上是某个其他基本描述符的数组。这对于作为另一个数据类型描述符中字段的数据类型描述符最有用途。如果此值非 NULL,则 fields 成员应为 NULL(但基本描述符的 fields 成员可以非 NULL)。

type PyArray_ArrayDescr#
typedef struct {
    PyArray_Descr *base;
    PyObject *shape;
} PyArray_ArrayDescr;
PyArray_Descr *base#

基本类型的描述符对象。

PyObject *shape#

子数组的形状(始终是 C 风格的连续数组),以 Python 元组的形式表示。

数据类型检查#

对于 typenum 宏,参数是一个表示枚举数组数据类型的整数。对于数组类型检查宏,参数必须是 PyObject*,可以直接将其解释为 PyArrayObject*

int PyTypeNum_ISUNSIGNED(int num)#
int PyDataType_ISUNSIGNED(PyArray_Descr *descr)#
int PyArray_ISUNSIGNED(PyArrayObject *obj)#

类型表示无符号整数。

int PyTypeNum_ISSIGNED(int num)#
int PyDataType_ISSIGNED(PyArray_Descr *descr)#
int PyArray_ISSIGNED(PyArrayObject *obj)#

类型表示有符号整数。

int PyTypeNum_ISINTEGER(int num)#
int PyDataType_ISINTEGER(PyArray_Descr *descr)#
int PyArray_ISINTEGER(PyArrayObject *obj)#

类型表示任何整数。

int PyTypeNum_ISFLOAT(int num)#
int PyDataType_ISFLOAT(PyArray_Descr *descr)#
int PyArray_ISFLOAT(PyArrayObject *obj)#

类型表示任何浮点数。

int PyTypeNum_ISCOMPLEX(int num)#
int PyDataType_ISCOMPLEX(PyArray_Descr *descr)#
int PyArray_ISCOMPLEX(PyArrayObject *obj)#

类型表示任何复数。

int PyTypeNum_ISNUMBER(int num)#
int PyDataType_ISNUMBER(PyArray_Descr *descr)#
int PyArray_ISNUMBER(PyArrayObject *obj)#

类型表示任何整数、浮点数或复数。

int PyTypeNum_ISSTRING(int num)#
int PyDataType_ISSTRING(PyArray_Descr *descr)#
int PyArray_ISSTRING(PyArrayObject *obj)#

类型表示字符串数据类型。

int PyTypeNum_ISFLEXIBLE(int num)#
int PyDataType_ISFLEXIBLE(PyArray_Descr *descr)#
int PyArray_ISFLEXIBLE(PyArrayObject *obj)#

类型表示以下灵活数组类型之一(NPY_STRINGNPY_UNICODENPY_VOID)。

int PyDataType_ISUNSIZED(PyArray_Descr *descr)#

类型没有附加大小信息,可以调整大小。只能对灵活的 dtype 调用。附加到数组的类型始终是已定大小的,因此此宏的数组形式不存在。

对于没有字段的结构化数据类型,此函数现在返回 False。

int PyTypeNum_ISUSERDEF(int num)#
int PyDataType_ISUSERDEF(PyArray_Descr *descr)#
int PyArray_ISUSERDEF(PyArrayObject *obj)#

类型表示用户定义的类型。

int PyTypeNum_ISEXTENDED(int num)#
int PyDataType_ISEXTENDED(PyArray_Descr *descr)#
int PyArray_ISEXTENDED(PyArrayObject *obj)#

类型是灵活的或用户定义的。

int PyTypeNum_ISOBJECT(int num)#
int PyDataType_ISOBJECT(PyArray_Descr *descr)#
int PyArray_ISOBJECT(PyArrayObject *obj)#

类型表示对象数据类型。

int PyTypeNum_ISBOOL(int num)#
int PyDataType_ISBOOL(PyArray_Descr *descr)#
int PyArray_ISBOOL(PyArrayObject *obj)#

类型表示布尔数据类型。

int PyDataType_HASFIELDS(PyArray_Descr *descr)#
int PyArray_HASFIELDS(PyArrayObject *obj)#

类型具有关联的字段。

int PyArray_ISNOTSWAPPED(PyArrayObject *m)#

当 ndarray m 的数据区域根据数组的数据类型描述符处于机器字节序时,求值为真。

int PyArray_ISBYTESWAPPED(PyArrayObject *m)#

当 ndarray m 的数据区域根据数组的数据类型描述符**不**处于机器字节序时,求值为真。

npy_bool PyArray_EquivTypes(PyArray_Descr *type1, PyArray_Descr *type2)#

如果 type1type2 实际上表示该平台的等效类型,则返回 NPY_TRUE(忽略每种类型的 fortran 成员)。例如,在 32 位平台上,NPY_LONGNPY_INT 是等效的。否则返回 NPY_FALSE

npy_bool PyArray_EquivArrTypes(PyArrayObject *a1, PyArrayObject *a2)#

如果 a1a2 是该平台的等效类型的数组,则返回 NPY_TRUE

npy_bool PyArray_EquivTypenums(int typenum1, int typenum2)#

PyArray_EquivTypes (…) 的特例,它不接受灵活的数据类型,但可能更容易调用。

int PyArray_EquivByteorders(int b1, int b2)#

如果字节序字符 b1b2NPY_LITTLENPY_BIGNPY_NATIVENPY_IGNORE )相等或在指定原生字节序方面等效,则返回 True。因此,在小端机器上,NPY_LITTLENPY_NATIVE 是等效的,而在大端机器上它们不等效。

转换数据类型#

PyObject *PyArray_Cast(PyArrayObject *arr, int typenum)#

主要用于向后兼容 Numeric C-API 和简单的非灵活类型转换。返回一个新的数组对象,其中 arr 的元素被转换为数据类型 typenumtypenum 必须是枚举类型之一,而不是灵活类型。

PyObject *PyArray_CastToType(PyArrayObject *arr, PyArray_Descr *type, int fortran)#

返回一个指定 type 的新数组,并将 arr 的元素适当地转换。fortran 参数指定输出数组的顺序。

int PyArray_CastTo(PyArrayObject *out, PyArrayObject *in)#

从 1.6 版本开始,此函数仅调用 PyArray_CopyInto,后者会处理转换。

将数组 in 的元素转换为数组 out。输出数组应该是可写的,其元素数量应为输入数组元素数量的整数倍(out 中可以容纳多个副本),并且数据类型必须是内置类型之一。成功时返回 0,出错时返回 -1。

int PyArray_CanCastSafely(int fromtype, int totype)#

如果数据类型为 fromtype 的数组可以安全地转换为数据类型为 totype 的数组而不会丢失信息,则返回非零值。一个例外是,允许将 64 位整数转换为 64 位浮点值,即使这可能会丢失大整数的精度,以便不普遍使用 long double 而不明确请求。灵活的数组类型不通过此函数检查其长度。

int PyArray_CanCastTo(PyArray_Descr *fromtype, PyArray_Descr *totype)#

在 NumPy 1.6 及更高版本中,PyArray_CanCastTypeTo 取代了此函数。

等同于 PyArray_CanCastTypeTo(fromtype, totype, NPY_SAFE_CASTING)。

int PyArray_CanCastTypeTo(PyArray_Descr *fromtype, PyArray_Descr *totype, NPY_CASTING casting)#

返回非零值,表示数据类型为 fromtype(可以包括灵活类型)的数组是否可以根据 casting 指定的转换规则安全地转换为数据类型为 totype(可以包括灵活类型)的数组。对于具有 NPY_SAFE_CASTING 的简单类型,这基本上是 PyArray_CanCastSafely 的包装器,但对于字符串或 Unicode 等灵活类型,它会考虑其大小来产生结果。只有当字符串或 Unicode 类型足够大以容纳被转换的整数/浮点类型的最大值时,整数和浮点类型才能使用 NPY_SAFE_CASTING 转换为字符串或 Unicode 类型。

int PyArray_CanCastArrayTo(PyArrayObject *arr, PyArray_Descr *totype, NPY_CASTING casting)#

根据 casting 中给出的转换规则,返回非零值,表示 arr 是否可以转换为 totype。如果 arr 是数组标量,则会考虑其值,并且当值不会溢出或截断为整数时(在转换为较小类型时),也会返回非零值。

PyArray_Descr *PyArray_MinScalarType(PyArrayObject *arr)#

注意

随着 NumPy 2 中 NEP 50 的采纳,此函数不在内部使用。它目前是为了向后兼容而提供的,但预计最终会被弃用。

如果 arr 是一个数组,则返回其数据类型描述符;如果 arr 是一个数组标量(维度为 0),则查找可以转换为该值而不会溢出或截断为整数的最小尺寸数据类型。

此函数不会将复数降级为浮点数或任何类型降级为布尔值,但当标量值为正时,会将有符号整数降级为无符号整数。

PyArray_Descr *PyArray_PromoteTypes(PyArray_Descr *type1, PyArray_Descr *type2)#

查找最小尺寸和类型的、type1type2 可以安全转换的数据类型。此函数是对称且可结合的。字符串或 Unicode 结果的大小将适合存储输入类型转换为字符串或 Unicode 的最大值。

PyArray_Descr *PyArray_ResultType(npy_intp narrs, PyArrayObject **arrs, npy_intp ndtypes, PyArray_Descr **dtypes)#

此函数将类型提升应用于所有输入数组和 dtype 对象,使用 NumPy 的规则组合标量和数组,以确定给定操作数集的输出类型。这与 ufunc 产生的类型相同。

有关类型提升算法的更多详细信息,请参阅 numpy.result_type 的文档。

int PyArray_ObjectType(PyObject *op, int mintype)#

此函数已被 PyArray_ResultType 取代。

此函数对于确定两个或多个数组可以转换为的公共类型很有用。它仅适用于非灵活的数组类型,因为没有传递项大小信息。mintype 参数表示可接受的最小类型,op 表示将被转换为数组的对象。返回值是表示 op 应具有的数据类型的枚举类型编号。

PyArrayObject **PyArray_ConvertToCommonType(PyObject *op, int *n)#

此函数提供的功能很大程度上已被 1.6 版本中引入的迭代器 NpyIter 所取代,该迭代器具有 NPY_ITER_COMMON_DTYPE 标志或所有操作数具有相同的 dtype 参数。

op 中包含的 Python 对象序列转换为数组,每个数组都具有相同的数据类型。类型选择方式与 PyArray_ResultType 相同。序列的长度返回在 n 中,返回值是一个包含 nPyArrayObject 指针的数组(如果发生错误则为 NULL)。返回的数组必须由调用此例程的调用者(使用 PyDataMem_FREE )释放,并且其中的所有数组对象都必须 DECREF ,否则将发生内存泄漏。下面的示例模板代码展示了典型用法。

mps = PyArray_ConvertToCommonType(obj, &n);
if (mps==NULL) return NULL;
{code}
<before return>
for (i=0; i<n; i++) Py_DECREF(mps[i]);
PyDataMem_FREE(mps);
{return}
char *PyArray_Zero(PyArrayObject *arr)#

指向新创建的内存的指针,大小为 arr ->itemsize,包含该类型的 0 的表示。返回的指针 ret 在不再需要时 **必须** 使用 PyDataMem_FREE (ret) 释放。

char *PyArray_One(PyArrayObject *arr)#

指向新创建的内存的指针,大小为 arr ->itemsize,包含该类型的 1 的表示。返回的指针 ret 在不再需要时 **必须** 使用 PyDataMem_FREE (ret) 释放。

int PyArray_ValidType(int typenum)#

如果 typenum 表示一个有效类型编号(内置、用户定义或字符代码),则返回 NPY_TRUE。否则,此函数返回 NPY_FALSE

用户定义的数据类型#

void PyArray_InitArrFuncs(PyArray_ArrFuncs *f)#

将所有函数指针和成员初始化为 NULL

int PyArray_RegisterDataType(PyArray_DescrProto *dtype)#

注意

从 NumPy 2.0 开始,此 API 被视为旧版 API,新的 DType API 更强大并提供更多灵活性。该 API 可能会被弃用,但目前仍受支持。

为 NumPy 1.x 和 2.x 编译

NumPy 2.x 要求传入一个 PyArray_DescrProto 类型的结构而不是 PyArray_Descr。这是为了允许更改。为了让代码在 1.x 和 2.x 上都能运行和编译,您需要将结构类型更改为 PyArray_DescrProto 并添加

/* Allow compiling on NumPy 1.x */
#if NPY_ABI_VERSION < 0x02000000
#define PyArray_DescrProto PyArray_Descr
#endif

以兼容 1.x。此外,结构将不再是实际的描述符,只会更新其类型编号。成功注册后,您必须使用以下方式获取实际的 dtype:

int type_num = PyArray_RegisterDataType(&my_descr_proto);
if (type_num < 0) {
    /* error */
}
PyArray_Descr *my_descr = PyArray_DescrFromType(type_num);

进行这两项更改后,代码应能在 1.x 和 2.x 或更高版本上编译和运行。

在极少数情况下,如果您在堆上分配 dtype 结构,则在 NumPy 2 中应再次释放它,因为会进行复制。该结构不是有效的 Python 对象,因此不要对其使用 Py_DECREF

将数据类型注册为数组的新用户定义数据类型。该类型必须填入大部分条目。并非总是会进行检查,错误可能导致段错误。特别是,dtype 结构中的 typeobj 成员必须填充一个 Python 类型,该类型具有与 dtype 的 elsize 成员对应的固定大小元素大小。此外,f 成员必须具有所需函数:nonzero、copyswap、copyswapn、getitem、setitem 和 cast(如果不需要支持,则一些 cast 函数可能为 NULL)。为避免混淆,您应该选择一个唯一的字符类型代码,但这并不强制执行,内部也不依赖于此。

返回一个唯一标识该类型的新用户定义类型编号。然后可以使用返回的类型编号通过 PyArray_DescrFromType 获取新结构的指针。如果发生错误,则返回 -1。如果此 dtype 已注册(仅通过指针地址检查),则返回先前分配的类型编号。

NumPy 已知用户 DType 的数量存储在 NPY_NUMUSERTYPES 中,这是一个公共的 C API 静态全局变量。访问此符号本质上 **不是** 线程安全的。如果出于某种原因您需要在多线程上下文中为此 API 使用此 API,则需要添加自己的锁定,NumPy 不保证可以以线程安全的方式添加新数据类型。

int PyArray_RegisterCastFunc(PyArray_Descr *descr, int totype, PyArray_VectorUnaryFunc *castfunc)#

注册一个低级转换函数 castfunc,用于将数据类型 descr 转换为给定的数据类型编号 totype。任何旧的转换函数都会被覆盖。成功时返回 0,失败时返回 -1。

type PyArray_VectorUnaryFunc#

低级转换函数的函数指针类型。

int PyArray_RegisterCanCast(PyArray_Descr *descr, int totype, NPY_SCALARKIND scalar)#

将数据类型编号 totype 注册为可从数据类型对象 descr(具有给定的 scalar 类型)进行转换。使用 scalar = NPY_NOSCALAR 来注册数据类型为 descr 的数组可以安全地转换为类型编号为 totype 的数据类型。返回值为 0 表示成功,-1 表示失败。

NPY_OBJECT 的特殊函数#

警告

在处理包含对象的数组或缓冲区时,NumPy 会尝试确保在读取任何数据之前将此类缓冲区填充为 None。然而,可能存在数组仅初始化为 NULL 的代码路径。NumPy 本身接受 NULL 作为 None 的别名,但在调试模式下编译时可能会断言非 NULL

由于 NumPy 尚未在初始化为 None 方面达成一致,用户在处理 NumPy 创建的缓冲区时 **必须** 期望值为 NULL。用户 **也应** 确保将完全初始化的缓冲区传递给 NumPy,因为 NumPy 未来可能会对此提出强制要求。

目前打算确保 NumPy 在读取任何数组之前始终对其进行初始化。任何未能这样做的都将被视为错误。将来,用户可能能够从任何数组读取非 NULL 值,但写入新创建数组(例如 ufunc 代码中的输出数组)的例外情况可能仍然存在。截至 NumPy 1.23,已知存在未正确填充的已知代码路径。

int PyArray_INCREF(PyArrayObject *op)#

用于包含任何 Python 对象的数组 op。它根据 op 的数据类型增加数组中每个对象的引用计数。如果发生错误,则返回 -1,否则返回 0。

void PyArray_Item_INCREF(char *ptr, PyArray_Descr *dtype)#

一个函数,根据数据类型 dtype 增加 ptr 位置上所有对象的引用计数。如果 ptr 是结构化类型(在任何偏移量处包含对象)的开头,则它将(递归地)增加结构化类型中所有对象类型项的引用计数。

int PyArray_XDECREF(PyArrayObject *op)#

用于包含任何 Python 对象的数组 op。它根据 op 的数据类型减少数组中每个对象的引用计数。正常返回值为 0。如果发生错误,则返回 -1。

void PyArray_Item_XDECREF(char *ptr, PyArray_Descr *dtype)#

一个函数,用于根据数据类型 dtype 中记录的位置 ptr 中的所有类对象项调用 XDECREF。这可以递归工作,因此如果 dtype 本身包含带有类对象项的数据类型的字段,则所有类对象字段都将被 XDECREF。

int PyArray_SetWritebackIfCopyBase(PyArrayObject *arr, PyArrayObject *base)#

先决条件:arrbase 的副本(尽管可能具有不同的步长、排序等)。设置 NPY_ARRAY_WRITEBACKIFCOPY 标志和 arr->base,并将 base 设置为 READONLY。在调用 Py_DECREF 之前调用 PyArray_ResolveWritebackIfCopy 以将任何更改复制回 base 并重置 READONLY 标志。

成功返回 0,失败返回 -1。

数组标志#

PyArrayObject 结构中的 flags 属性包含有关数组内存(由 data 成员指向)的重要信息。此标志信息必须保持准确,否则可能导致奇怪的结果甚至段错误。

有 6 个(二进制)标志描述数据缓冲区使用的内存区域。这些常量定义在 arrayobject.h 中,并确定标志的位位置。Python 也提供了一个方便的基于属性的接口和一个类似字典的接口来获取(以及在适当的情况下设置)这些标志。

各种类型的内存区域都可以由 ndarray 指向,这使得这些标志成为必需。如果您在 C 代码中获得任意 PyArrayObject,您需要了解已设置的标志。如果您需要保证某种类型的数组(如 NPY_ARRAY_C_CONTIGUOUSNPY_ARRAY_BEHAVED),则将这些要求传递给 PyArray_FromAny 函数。

在 NumPy 的 1.6 及更早版本中,以下标志没有 _ARRAY_ 宏命名空间。1.7 版本中已弃用该形式的常量名称。

基本数组标志#

ndarray 可以有一个数据段,它不是一个你可以操作的简单连续的、行为良好的内存块。它可能没有与字边界对齐(在某些平台上非常重要)。它可能具有与机器识别的字节顺序不同的字节顺序。它可能不可写。它可能以 Fortran 连续顺序存储。数组标志用于指示关于与数组相关的数据可以说什么。

NPY_ARRAY_C_CONTIGUOUS#

数据区域采用 C 风格连续顺序(最后一个索引变化最快)。

NPY_ARRAY_F_CONTIGUOUS#

数据区域采用 Fortran 风格连续顺序(第一个索引变化最快)。

注意

数组可以同时是 C 风格和 Fortran 风格的连续的。这对于一维数组来说很清楚,但对于更高维度的数组也可能如此。

即使对于连续数组,如果 arr.shape[dim] == 1 或数组没有元素,给定维度 arr.strides[dim] 的步幅也可能是*任意*的。通常不成立 self.strides[-1] == self.itemsize 对于 C 风格连续数组,或者 self.strides[0] == self.itemsize 对于 Fortran 风格连续数组。从 C API 访问数组的 itemsize 的正确方法是 PyArray_ITEMSIZE(arr)

NPY_ARRAY_OWNDATA#

数据区域由此数组拥有。绝不应手动设置,而是创建一个包装数据的 PyObject 并将数组的基对象设置为该对象。例如,请参阅 test_mem_policy 中的测试。

NPY_ARRAY_ALIGNED#

数据区域和所有数组元素都已正确对齐。

NPY_ARRAY_WRITEABLE#

数据区域可写入。

请注意,上述 3 个标志的定义方式使得一个新创建的、行为良好的数组具有这些标志为 true。

NPY_ARRAY_WRITEBACKIFCOPY#

数据区域代表一个(行为良好的)副本,其信息应在调用 PyArray_ResolveWritebackIfCopy 时传输回原始数据。

这是一个特殊标志,如果此数组代表用户在 PyArray_FromAny 中要求某些标志而必须复制其他数组(并且用户在这种情况下要求设置此标志)所制作的副本,则会设置此标志。然后,基对象指向“行为不端”的数组(该数组被设置为只读)。 PyArray_ResolveWritebackIfCopy 会将其内容复制回“行为不端”的数组(必要时进行类型转换),并将“行为不端”的数组重置为 NPY_ARRAY_WRITEABLE。如果“行为不端”的数组最初就不是 NPY_ARRAY_WRITEABLE,则 PyArray_FromAny 将返回错误,因为 NPY_ARRAY_WRITEBACKIFCOPY 将无法实现。

PyArray_UpdateFlags (obj, flags) 将更新 obj->flags 以匹配 flags,后者可以是 NPY_ARRAY_C_CONTIGUOUSNPY_ARRAY_F_CONTIGUOUSNPY_ARRAY_ALIGNEDNPY_ARRAY_WRITEABLE 中的任意一个。

数组标志的组合#

NPY_ARRAY_BEHAVED#

NPY_ARRAY_ALIGNED | NPY_ARRAY_WRITEABLE

NPY_ARRAY_CARRAY#

NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_BEHAVED

NPY_ARRAY_CARRAY_RO#

NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED

NPY_ARRAY_FARRAY#

NPY_ARRAY_F_CONTIGUOUS | NPY_ARRAY_BEHAVED

NPY_ARRAY_FARRAY_RO#

NPY_ARRAY_F_CONTIGUOUS | NPY_ARRAY_ALIGNED

NPY_ARRAY_DEFAULT#

NPY_ARRAY_CARRAY

NPY_ARRAY_IN_ARRAY#

NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED

NPY_ARRAY_IN_FARRAY#

NPY_ARRAY_F_CONTIGUOUS | NPY_ARRAY_ALIGNED

NPY_ARRAY_OUT_ARRAY#

NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_WRITEABLE | NPY_ARRAY_ALIGNED

NPY_ARRAY_OUT_FARRAY#

NPY_ARRAY_F_CONTIGUOUS | NPY_ARRAY_WRITEABLE | NPY_ARRAY_ALIGNED

NPY_ARRAY_INOUT_ARRAY#

NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_WRITEABLE | NPY_ARRAY_ALIGNED | NPY_ARRAY_WRITEBACKIFCOPY

NPY_ARRAY_INOUT_FARRAY#

NPY_ARRAY_F_CONTIGUOUS | NPY_ARRAY_WRITEABLE | NPY_ARRAY_ALIGNED | NPY_ARRAY_WRITEBACKIFCOPY

NPY_ARRAY_UPDATE_ALL#

NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_F_CONTIGUOUS | NPY_ARRAY_ALIGNED

类似标志的常量#

这些常量用于 PyArray_FromAny(及其宏形式)中,以指定新数组的期望属性。

NPY_ARRAY_FORCECAST#

强制转换为期望的类型,即使不能在不丢失信息的情况下进行转换。

NPY_ARRAY_ENSURECOPY#

确保结果数组是原始数组的副本。

NPY_ARRAY_ENSUREARRAY#

确保结果对象是一个实际的 ndarray,而不是子类。

这些常量用于 PyArray_CheckFromAny(及其宏形式)中,以指定新数组的期望属性。

NPY_ARRAY_NOTSWAPPED#

确保返回的数组具有机器字节序的数据类型描述符,覆盖 dtype 参数中的任何规范。通常,字节序要求由 dtype 参数确定。如果设置了此标志,并且 dtype 参数未指示机器字节序描述符(或为 NULL,并且对象已经是具有非机器字节序数据类型描述符的数组),则会创建一个新的数据类型描述符并使用其字节序字段设置为本机。

NPY_ARRAY_BEHAVED_NS#

NPY_ARRAY_ALIGNED | NPY_ARRAY_WRITEABLE | NPY_ARRAY_NOTSWAPPED

NPY_ARRAY_ELEMENTSTRIDES#

确保返回的数组的步幅是元素大小的倍数。

标志检查#

对于所有这些宏,arr 必须是 PyArray_Type 的一个实例(或子类)。

int PyArray_CHKFLAGS(const PyArrayObject *arr, int flags)#

第一个参数 arr 必须是 ndarray 或其子类。参数 flags 应为一个整数,由数组可以拥有的可能标志的按位组合构成: NPY_ARRAY_C_CONTIGUOUSNPY_ARRAY_F_CONTIGUOUSNPY_ARRAY_OWNDATANPY_ARRAY_ALIGNEDNPY_ARRAY_WRITEABLENPY_ARRAY_WRITEBACKIFCOPY

int PyArray_IS_C_CONTIGUOUS(const PyArrayObject *arr)#

如果 arr 是 C 风格连续的,则评估为 true。

int PyArray_IS_F_CONTIGUOUS(const PyArrayObject *arr)#

如果 arr 是 Fortran 风格连续的,则评估为 true。

int PyArray_ISFORTRAN(const PyArrayObject *arr)#

如果 arr 是 Fortran 风格连续的*且不是* C 风格连续的,则评估为 true。 PyArray_IS_F_CONTIGUOUS 是测试 Fortran 风格连续性的正确方法。

int PyArray_ISWRITEABLE(const PyArrayObject *arr)#

如果 arr 的数据区域可写入,则评估为 true。

int PyArray_ISALIGNED(const PyArrayObject *arr)#

如果 arr 的数据区域在机器上正确对齐,则评估为 true。

int PyArray_ISBEHAVED(const PyArrayObject *arr)#

如果 arr 的数据区域根据其描述符是已对齐、可写入且为机器字节序,则评估为 true。

int PyArray_ISBEHAVED_RO(const PyArrayObject *arr)#

如果 arr 的数据区域是已对齐且为机器字节序,则评估为 true。

int PyArray_ISCARRAY(const PyArrayObject *arr)#

如果 arr 的数据区域是 C 风格连续的,并且 PyArray_ISBEHAVED(arr) 为 true,则评估为 true。

int PyArray_ISFARRAY(const PyArrayObject *arr)#

如果 arr 的数据区域是 Fortran 风格连续的,并且 PyArray_ISBEHAVED(arr) 为 true,则评估为 true。

int PyArray_ISCARRAY_RO(const PyArrayObject *arr)#

如果 arr 的数据区域是 C 风格连续的、已对齐且为机器字节序,则评估为 true。

int PyArray_ISFARRAY_RO(const PyArrayObject *arr)#

如果 arr 的数据区域是 Fortran 风格连续的、已对齐且为机器字节序**,则评估为 true。**

int PyArray_ISONESEGMENT(const PyArrayObject *arr)#

如果 arr 的数据区域由单个(C 风格或 Fortran 风格)连续段组成,则评估为 true。

void PyArray_UpdateFlags(PyArrayObject *arr, int flagmask)#

NPY_ARRAY_C_CONTIGUOUSNPY_ARRAY_ALIGNEDNPY_ARRAY_F_CONTIGUOUS 数组标志可以从数组对象本身“计算”得出。此例程通过执行所需计算来更新 arr 的一个或多个标志,具体由 flagmask 指定。

警告

当对数组执行可能导致标志更改的操作时,保持标志更新(可以通过 PyArray_UpdateFlags 来协助)非常重要。NumPy 中依赖这些标志状态的后续计算不会重复计算以更新它们。

int PyArray_FailUnlessWriteable(PyArrayObject *obj, const char *name)#

如果 obj 是可写的,此函数不做任何事并返回 0。如果 obj 不可写,它将引发异常并返回 -1。它还可能执行其他维护操作,例如在即将变为视图的数组上发出警告。始终在写入数组的某个时候调用此函数。

name 是数组的名称,用于提供更好的错误消息。它可以是“赋值目标”、“输出数组”甚至“数组”等内容。

ArrayMethod API#

ArrayMethod 循环旨在作为编写数组循环的通用机制,包括 ufunc 循环和类型转换。公共 API 定义在 numpy/dtype_api.h 头文件中。有关 ArrayMethod API 中暴露的 C 结构体的文档,请参阅 PyArrayMethod_Context and PyArrayMethod_Spec

槽和类型定义#

这些用于标识 ArrayMethod 槽实现的函数类型。有关每个槽必须实现的函数的文档,请参阅下面的 槽和类型定义

NPY_METH_resolve_descriptors#
typedef NPY_CASTING (PyArrayMethod_ResolveDescriptors)(struct PyArrayMethodObject_tag *method, PyArray_DTypeMeta *const *dtypes, PyArray_Descr *const *given_descrs, PyArray_Descr **loop_descrs, npy_intp *view_offset)#

用于根据操作数描述符设置操作描述符的函数。例如,一个具有两个输入操作数和一个输出操作数的 ufunc 操作,在 Python API 中未设置 out 时调用,resolve_descriptors 将接收两个操作数的描述符,并根据 ArrayMethod 设置的输出 DType 确定输出的正确描述符。如果设置了 out,则也将传递输出描述符,并且不应覆盖它。

method 是指向底层类型转换或 ufunc 循环的指针。将来我们可能会公开此结构体,但目前这是一个不透明指针,无法检查方法。dtypes 是一个 nargs 长度的 PyArray_DTypeMeta 指针数组,given_descrs 是一个 nargs 长度的输入描述符实例数组(如果没有由用户提供的输出,则输出描述符可能为 NULL),loop_descrs 是一个 nargs 长度的描述符数组,必须由 resolve_descriptors 实现填充。view_offset 目前仅对类型转换有意义,通常可以忽略。当类型转换不需要任何操作时,可以通过将 view_offset 设置为 0 来发出信号。出错时,必须返回 (NPY_CASTING)-1 并设置错误。

NPY_METH_strided_loop#
NPY_METH_contiguous_loop#
NPY_METH_unaligned_strided_loop#
NPY_METH_unaligned_contiguous_loop#

实现行为(ufunc 或 cast)的一维跨步循环。在大多数情况下,NPY_METH_strided_loop 是通用且唯一需要实现的版本。可以另外实现NPY_METH_contiguous_loop 作为更轻量级/更快的版本,当所有输入和输出都是连续的时使用它。

为了处理可能未对齐的数据,NumPy 需要能够将未对齐的数据复制到已对齐的数据。在实现新的 DType 时,“cast”或复制需要实现NPY_METH_unaligned_strided_loop。与普通版本不同,此循环不能假定数据可以以已对齐的方式访问。这些循环在访问或存储之前必须复制每个值

type_in in_value;
type_out out_value
memcpy(&value, in_data, sizeof(type_in));
out_value = in_value;
memcpy(out_data, &out_value, sizeof(type_out)

而普通循环可以只使用

*(type_out *)out_data = *(type_in)in_data;

未对齐的循环目前仅在 cast 中使用,并且永远不会在 ufuncs 中被选中(ufuncs 会创建临时副本以确保已对齐的输入)。当定义了NPY_METH_get_loop 时,这些 slot ID 会被忽略,而是使用get_loop函数返回的任何循环。

NPY_METH_contiguous_indexed_loop#

一个专门的内部循环选项,用于加速常见的 ufunc.at 计算。

typedef int (PyArrayMethod_StridedLoop)(PyArrayMethod_Context *context, char *const *data, const npy_intp *dimensions, const npy_intp *strides, NpyAuxData *auxdata)#

ArrayMethod 循环的实现。上面列出的所有循环 slot ID 都必须提供 PyArrayMethod_StridedLoop 实现。context 是一个包含循环操作上下文的结构体 - 特别是输入描述符。data 是指向输入和输出数组缓冲区开头的指针数组。dimensions 是操作的循环维度。strides 是每个输入的步幅的 nargs 长度数组。auxdata 是一个可选的辅助数据集合,可以传递给循环 - 这有助于打开和关闭可选行为,或者通过允许类似的 ufuncs 共享循环实现或分配持久化到多个跨步循环调用的空间来减少样板代码。

NPY_METH_get_loop#

允许对循环选择进行更精细控制。接受 PyArrayMethod_GetLoop 的实现,该实现反过来返回一个跨步循环实现。如果定义了 NPY_METH_get_loop,则忽略其他指定的循环 slot ID。

typedef int (PyArrayMethod_GetLoop)(PyArrayMethod_Context *context, int aligned, int move_references, const npy_intp *strides, PyArrayMethod_StridedLoop **out_loop, NpyAuxData **out_transferdata, NPY_ARRAYMETHOD_FLAGS *flags);#

在运行时设置用于操作的循环。context 是操作的运行时上下文。aligned 指示循环的数据访问是已对齐 (1) 还是未对齐 (0)。move_references 指示数据中的嵌入引用是否应该被复制。strides 是输入数组的步幅,out_loop 是一个必须被填充为指向循环实现的指针。out_transferdata 可以选择性地填充,以允许将额外的用户定义上下文传递给操作。flags 必须被填充为与操作相关的 ArrayMethod 标志。例如,这对于指示内部循环是否需要持有 Python GIL 是必要的。

NPY_METH_get_reduction_initial#
typedef int (PyArrayMethod_GetReductionInitial)(PyArrayMethod_Context *context, npy_bool reduction_is_empty, char *initial)#

查询 ArrayMethod 以获取用于归约的初始值。context 是 ArrayMethod 上下文,主要是为了访问输入描述符。reduction_is_empty 指示归约是否为空。当它为空时,返回值可能不同。在这种情况下,它是一个“默认”值,可能与通常使用的“恒等”值不同。例如

  • 0.0sum([]) 的默认值。但是 -0.0 是正确的恒等值,因为它保留了 sum([-0.0]) 的符号。

  • 对于 object 类型,我们不使用恒等式,而是返回 sum([], dtype=object)prod([], dtype=object) 的默认值 01。这使得 np.sum(np.array(["a", "b"], dtype=object)) 能够工作。

  • max-infINT_MIN 是一个恒等式,但至少 INT_MIN 在没有元素时不是一个好的默认值。

initial 是指向初始值数据的指针,应该被填充。返回 -1、0 或 1,分别表示错误、没有初始值以及成功填充初始值。当没有正确的初始值时,不应出现错误,因为 NumPy 可能会调用此函数,即使它并非严格必要。

Flags#

enum NPY_ARRAYMETHOD_FLAGS#

这些标志允许为 ArrayMethod 循环切换自定义运行时行为。例如,如果一个 ufunc 不可能触发浮点错误,那么当 ufunc 注册时,应该为该 ufunc 设置 NPY_METH_NO_FLOATINGPOINT_ERRORS 标志。

enumerator NPY_METH_REQUIRES_PYAPI#

指示方法必须持有 GIL。如果未设置此标志,则在调用循环之前会释放 GIL。

enumerator NPY_METH_NO_FLOATINGPOINT_ERRORS#

指示方法不能产生浮点错误,因此可以跳过循环完成后对浮点错误的检查。

enumerator NPY_METH_SUPPORTS_UNALIGNED#

指示方法支持未对齐访问。

enumerator NPY_METH_IS_REORDERABLE#

指示重复应用循环(例如,在归约操作中)的结果不取决于应用的顺序。

enumerator NPY_METH_RUNTIME_FLAGS#

可以在运行时更改的标志。

Typedefs#

下面将描述 ArrayMethod API 用户可以实现的函数的 Typedefs。

typedef int (PyArrayMethod_TraverseLoop)(void *traverse_context, const PyArray_Descr *descr, char *data, npy_intp size, npy_intp stride, NpyAuxData *auxdata)#

一个处理单个数组的 traverse 循环。这类似于通用的跨步循环函数。它旨在用于需要访问单个数组中每个元素的循环。

目前,它通过 NPY_DT_get_clear_loop DType API 钩子用于数组清除,通过 NPY_DT_get_fill_zero_loop DType API 钩子用于零填充。这些对于处理存储 Python 对象或堆分配数据的嵌入式引用的数组最有帮助。

descr 是数组的描述符,data 是指向数组缓冲区的指针,size 是数组缓冲区的 1D 大小,stride 是步幅,auxdata 是循环的可选额外数据。

traverse_context 被传入,因为将来我们可能需要传入解释器状态或类似的东西,但我们不想传入完整的上下文(带有指向 dtype、方法、调用者的指针,这些对于 traverse 函数都没有意义)。我们目前假设将来可以将此上下文直接传递(对于结构化 dtype)。

typedef int (PyArrayMethod_GetTraverseLoop)(void *traverse_context, const PyArray_Descr *descr, int aligned, npy_intp fixed_stride, PyArrayMethod_TraverseLoop **out_loop, NpyAuxData **out_auxdata, NPY_ARRAYMETHOD_FLAGS *flags)#

特定于 dtype 遍历的简化 get_loop 函数

它应该设置遍历循环所需的标志,并将out_loop设置为循环函数,该函数必须是指向有效的 PyArrayMethod_TraverseLoop 的指针。目前,这用于零填充和清除存储嵌入式引用的数组。

API Functions and Typedefs#

这些函数是主 numpy 数组 API 的一部分,并与 ArrayMethod API 的其余部分一起添加。

int PyUFunc_AddLoopFromSpec(PyObject *ufunc, PyArrayMethod_Spec *spec)#

从给定的 ArrayMethod spec 直接向 ufunc 添加循环。这是主要的 ufunc 注册函数。它向 ufunc 添加一个新的实现/循环。它取代 PyUFunc_RegisterLoopForType

type PyUFunc_LoopSlot#

用于从 ArrayMethod spec 向 ufuncs 添加多个循环的结构。这在 PyUFunc_AddLoopsFromSpecs 中使用。

struct PyUFunc_LoopSlot#
const char *name#

要向其添加循环的 ufunc 的名称,格式类似于入口点,(module ':')? (object '.')* name,其中 numpy 是默认模块。示例:sinstrings.str_lennumpy.strings:str_len

PyArrayMethod_Spec *spec#

用于创建循环的 ArrayMethod spec。

int PyUFunc_AddLoopsFromSpecs(PyUFunc_LoopSlot *slots)#

版本 2.4 中的新功能。

从 ArrayMethod spec 向 ufuncs 添加多个循环。这还负责为 ufunc 类函数 sortargsort 注册方法。有关详细信息,请参阅 Sorting and Argsorting

slots 参数必须是 PyUFunc_LoopSlot 的 NULL 终止数组(见上文),它提供了创建循环所需的 ufunc 名称和 spec。

int PyUFunc_AddPromoter(PyObject *ufunc, PyObject *DType_tuple, PyObject *promoter)#

请注意,目前输出 dtype 始终是 NULL,除非它们也是签名的一部分。这是一个实现细节,未来可能会改变。但是,一般而言,promoter 不需要输出 dtype。为 ufunc 注册一个新的 promoter。第一个参数是要注册 promoter 的 ufunc。第二个参数是一个包含 DTypes 或 None 的 Python 元组,匹配 ufuncs 的输入和输出数量。最后一个参数是一个存储在 PyCapsule 中的 promoter 函数。它会接收操作和请求的 DType 签名,并可以修改它们以尝试新的匹配循环/promoter 的搜索。

typedef int (PyArrayMethod_PromoterFunction)(PyObject *ufunc, PyArray_DTypeMeta *const op_dtypes[], PyArray_DTypeMeta *const signature[], PyArray_DTypeMeta *new_op_dtypes[])#

promoter 函数的类型,它必须被封装到一个名为 "numpy._ufunc_promoter"PyCapsule 中。它接收操作和请求的 DType 签名,并可以修改签名以尝试搜索新的循环或 promoter,通过将输入强制转换为“promoted” DTypes 来完成操作。

int PyUFunc_GiveFloatingpointErrors(const char *name, int fpe_errors)#

在执行浮点操作后检查浮点错误,其方式考虑到通过 numpy.errstate 配置的错误信号。接受操作的名称以用于错误消息,以及一个整数标志,该标志是 NPY_FPE_DIVIDEBYZERONPY_FPE_OVERFLOWNPY_FPE_UNDERFLOWNPY_FPE_INVALID 之一,以指示要检查的错误。

失败时返回 -1(已引发错误),成功时返回 0。

int PyUFunc_AddWrappingLoop(PyObject *ufunc_obj, PyArray_DTypeMeta *new_dtypes[], PyArray_DTypeMeta *wrapped_dtypes[], PyArrayMethod_TranslateGivenDescriptors *translate_given_descrs, PyArrayMethod_TranslateLoopDescriptors *translate_loop_descrs)#

允许围绕现有 ufunc 循环创建相当轻量级的包装器。该想法主要用于单位(units),因为目前它有些限制,强制规定您不能使用来自其他 ufunc 的循环。

typedef int (PyArrayMethod_TranslateGivenDescriptors)(int nin, int nout, PyArray_DTypeMeta *wrapped_dtypes[], PyArray_Descr *given_descrs[], PyArray_Descr *new_descrs[]);#

用于转换传递给 resolve_descriptors 的描述符并为包装的循环转换它们。新的描述符 **必须** 可以用旧的描述符视图化,NULL 必须被支持(对于输出参数),并且通常应该被转发。

此函数将用于构建参数视图,就好像它们是转换后的 dtype 一样,并且不使用 cast。这意味着此机制主要对“包装”另一个 DType 实现的 DTypes 有用。例如,一个单元 DType 可以使用此功能来包装现有的浮点 DType,而无需重新实现底层 ufunc 逻辑。在单元示例中,resolve_descriptors 将负责从输入单元计算输出单元。

typedef int (PyArrayMethod_TranslateLoopDescriptors)(int nin, int nout, PyArray_DTypeMeta *new_dtypes[], PyArray_Descr *given_descrs[], PyArray_Descr *original_descrs[], PyArray_Descr *loop_descrs[]);#

将实际的循环描述符(由原始 `resolve_descriptors` 函数返回)转换为输出数组应使用的描述符。此函数必须返回“可视图”类型,并且不得以任何会破坏内部循环逻辑的方式对其进行变异。无需支持 NULL。

包装循环示例#

假设您想为 `WrappedDoubleDType` 包装 `float64` 乘法实现。您可以像这样添加一个包装循环:

PyArray_DTypeMeta *orig_dtypes[3] = {
    &WrappedDoubleDType, &WrappedDoubleDType, &WrappedDoubleDType};
PyArray_DTypeMeta *wrapped_dtypes[3] = {
     &PyArray_Float64DType, &PyArray_Float64DType, &PyArray_Float64DType}

PyObject *mod = PyImport_ImportModule("numpy");
if (mod == NULL) {
    return -1;
}
PyObject *multiply = PyObject_GetAttrString(mod, "multiply");
Py_DECREF(mod);

if (multiply == NULL) {
    return -1;
}

int res = PyUFunc_AddWrappingLoop(
    multiply, orig_dtypes, wrapped_dtypes, &translate_given_descrs
    &translate_loop_descrs);

Py_DECREF(multiply);

请注意,这还需要在此代码上方定义两个函数。

static int
translate_given_descrs(int nin, int nout,
                       PyArray_DTypeMeta *NPY_UNUSED(wrapped_dtypes[]),
                       PyArray_Descr *given_descrs[],
                       PyArray_Descr *new_descrs[])
{
    for (int i = 0; i < nin + nout; i++) {
        if (given_descrs[i] == NULL) {
            new_descrs[i] = NULL;
        }
        else {
            new_descrs[i] = PyArray_DescrFromType(NPY_DOUBLE);
        }
    }
    return 0;
}

static int
translate_loop_descrs(int nin, int NPY_UNUSED(nout),
                      PyArray_DTypeMeta *NPY_UNUSED(new_dtypes[]),
                      PyArray_Descr *given_descrs[],
                      PyArray_Descr *original_descrs[],
                      PyArray_Descr *loop_descrs[])
{
    // more complicated parametric DTypes may need to
    // to do additional checking, but we know the wrapped
    // DTypes *have* to be float64 for this example.
    loop_descrs[0] = PyArray_DescrFromType(NPY_FLOAT64);
    Py_INCREF(loop_descrs[0]);
    loop_descrs[1] = PyArray_DescrFromType(NPY_FLOAT64);
    Py_INCREF(loop_descrs[1]);
    loop_descrs[2] = PyArray_DescrFromType(NPY_FLOAT64);
    Py_INCREF(loop_descrs[2]);
}

排序和 argsort#

可以使用 ArrayMethod API 注册数据类型的排序和 argsort 方法。这是通过添加名称为 `"sort"` 或 `"argsort"` 的 ArrayMethod 规范来实现的。对于 sort 和 argsort,规范必须具有 `nin=1` 和 `nout=1`。排序是就地进行的,因此我们强制要求 `data[0] == data[1]`。Argsort 返回一个新的索引数组,因此输出必须是 `NPY_INTP` 类型。

传递给循环的 `context` 包含 `parameters` 字段,该字段对于这些操作是 `PyArrayMethod_SortParameters *` 结构。此结构包含一个 `flags` 字段,该字段是 `NPY_SORTKIND` 值的按位 OR,指示要执行的排序类型(即,它是稳定排序和/或降序排序)。如果跨步循环依赖于标志,一种处理此问题的好方法是定义 `NPY_METH_get_loop`,而不设置任何其他循环槽。

struct PyArrayMethod_SortParameters#
NPY_SORTKIND flags#

传递给排序操作的标志。这是 `NPY_SORTKIND` 值的按位 OR,指示要执行的排序类型。

这些规范可以与 ufunc 循环一起通过 `PyUFunc_AddLoopsFromSpecs` 注册。

调用数组方法的 API#

转换#

PyObject *PyArray_GetField(PyArrayObject *self, PyArray_Descr *dtype, int offset)#

相当于 `ndarray.getfield` (*self*, *dtype*, *offset*)。此函数 窃取对 `PyArray_Descr` 的引用,并使用当前数组在指定字节偏移量处的数据返回一个具有给定 `dtype` 的新数组。`offset` 加上新数组类型的 `itemsize` 必须小于 `self->descr->elsize`,否则会引发错误。使用与原始数组相同的形状和跨步。因此,此函数的作用是返回结构化数组的字段。但是,它也可以用于从任何数组类型中选择特定的字节或字节组。

int PyArray_SetField(PyArrayObject *self, PyArray_Descr *dtype, int offset, PyObject *val)#

相当于 `ndarray.setfield` (*self*, *val*, *dtype*, *offset*)。设置从字节偏移量 `offset` 开始、`dtype` 类型为 `dtype` 的字段为 `val`。`offset` 加上 `dtype` ->elsize 必须小于 `self` ->descr->elsize,否则会引发错误。否则,`val` 参数将被转换为数组并复制到字段指针中。如果需要,`val` 的元素会被重复以填充目标数组。但是,目标中的元素数量必须是 `val` 中的元素数量的整数倍。

PyObject *PyArray_Byteswap(PyArrayObject *self, npy_bool inplace)#

相当于 `ndarray.byteswap` (*self*, *inplace*)。返回一个数据区域经过字节交换的数组。如果 `inplace` 非零,则就地进行字节交换并返回 `self` 的引用。否则,创建字节交换的副本并保持 `self` 不变。

PyObject *PyArray_NewCopy(PyArrayObject *old, NPY_ORDER order)#

相当于 `ndarray.copy` (*self*, *fortran*)。复制 `old` 数组。返回的数组始终是已对齐且可写的,其数据解释与旧数组相同。如果 `order` 是 `NPY_CORDER`,则返回 C 风格的连续数组。如果 `order` 是 `NPY_FORTRANORDER`,则返回 Fortran 风格的连续数组。如果 `order` 是 `NPY_ANYORDER`,则仅当旧数组是 Fortran 风格的连续数组时,返回的数组才是 Fortran 风格的连续数组;否则,它是 C 风格的连续数组。

PyObject *PyArray_ToList(PyArrayObject *self)#

相当于 `ndarray.tolist` (*self*)。从 `self` 返回一个嵌套的 Python 列表。

PyObject *PyArray_ToString(PyArrayObject *self, NPY_ORDER order)#

相当于 `ndarray.tobytes` (*self*, *order*)。以 Python 字符串形式返回此数组的字节。

PyObject *PyArray_ToFile(PyArrayObject *self, FILE *fp, char *sep, char *format)#

以 C 风格的连续方式将 `self` 的内容写入文件指针 `fp`。如果 `sep` 是字符串 "" 或 `NULL`,则以二进制字节形式写入数据。否则,以文本形式写入 `self` 的内容,使用 `sep` 字符串作为项分隔符。每个项将打印到文件。如果 `format` 字符串不是 `NULL` 或 "",则它是一个 Python 打印语句格式字符串,显示项如何写入。

int PyArray_Dump(PyObject *self, PyObject *file, int protocol)#

将 `self` 中的对象 pickle 到给定的 `file`(字符串或 Python 文件对象)。如果 `file` 是 Python 字符串,则将其视为文件名,然后以二进制模式打开。使用给定的 `protocol`(如果 `protocol` 为负,则使用最高可用协议)。这是 cPickle.dump(*self*, *file*, *protocol*) 的简单包装。

PyObject *PyArray_Dumps(PyObject *self, int protocol)#

将 `self` 中的对象 pickle 到 Python 字符串并返回它。使用提供的 Pickle `protocol`(如果 `protocol` 为负,则使用最高可用协议)。

int PyArray_FillWithScalar(PyArrayObject *arr, PyObject *obj)#

用给定的标量对象 `obj` 填充数组 `arr`。该对象首先被转换为 `arr` 的数据类型,然后复制到每个位置。如果发生错误,则返回 -1,否则返回 0。

PyObject *PyArray_View(PyArrayObject *self, PyArray_Descr *dtype, PyTypeObject *ptype)#

相当于 `ndarray.view` (*self*, *dtype*)。返回数组 `self` 的新视图,可能具有不同的数据类型 `dtype` 和不同的数组子类 `ptype`。

如果 `dtype` 是 `NULL`,则返回的数组将具有与 `self` 相同的数据类型。新数据类型必须与 `self` 的大小兼容。要么 `itemsizes` 必须相同,要么 `self` 必须是单段的,并且总字节数必须相同。在后一种情况下,返回数组的维度将在最后一个维度(或对于 Fortran 风格的连续数组,第一个维度)上改变。返回数组和 `self` 的数据区域完全相同。

形状操作#

PyObject *PyArray_Newshape(PyArrayObject *self, PyArray_Dims *newshape, NPY_ORDER order)#

结果将是一个新数组(如果可能,指向与 `self` 相同的内存位置),但其形状由 `newshape` 指定。如果新形状与 `self` 的跨步不兼容,则将返回一个具有新指定形状的数组副本。

PyObject *PyArray_Reshape(PyArrayObject *self, PyObject *shape)#

相当于 `ndarray.reshape` (*self*, *shape*),其中 `shape` 是一个序列。将 `shape` 转换为 `PyArray_Dims` 结构并内部调用 `PyArray_Newshape`。为了向后兼容 - 不推荐。

PyObject *PyArray_Squeeze(PyArrayObject *self)#

相当于 `ndarray.squeeze` (*self*)。返回 `self` 的新视图,其中所有长度为 1 的维度都已从形状中移除。

警告

矩阵对象始终是二维的。因此,`PyArray_Squeeze` 对矩阵子类数组没有影响。

PyObject *PyArray_SwapAxes(PyArrayObject *self, int a1, int a2)#

相当于 `ndarray.swapaxes` (*self*, *a1*, *a2*)。返回的数组是 `self` 数据的新视图,其中给定的轴 `a1` 和 `a2` 已交换。

PyObject *PyArray_Resize(PyArrayObject *self, PyArray_Dims *newshape, int refcheck, NPY_ORDER fortran)#

相当于 `ndarray.resize` (*self*, *newshape*, *refcheck*)。此函数仅适用于单段数组。它会就地更改 `self` 的形状,如果 `newshape` 的总元素数量与旧形状不同,则会重新分配 `self` 的内存。如果需要重新分配,则 `self` 必须拥有其数据,`self`->base==NULL,`self`->weakrefs==NULL,并且(除非 refcheck 为 0)不被任何其他数组引用。fortran 参数可以是 `NPY_ANYORDER`、`NPY_CORDER` 或 `NPY_FORTRANORDER`。目前它没有影响。最终,它可用于确定在构造不同维度的数组时,resize 操作应该如何查看数据。成功时返回 None,错误时返回 NULL。

PyObject *PyArray_Transpose(PyArrayObject *self, PyArray_Dims *permute)#

相当于 `ndarray.transpose` (*self*, *permute*)。根据数据结构 `permute` 置换 ndarray 对象 `self` 的轴并返回结果。如果 `permute` 是 `NULL`,则结果数组的轴将被反转。例如,如果 `self` 的形状是 \(10\times20\times30\),并且 `permute`.ptr 是 (0,2,1),则结果的形状是 \(10\times30\times20\)。如果 `permute` 是 `NULL`,则结果的形状是 \(30\times20\times10\)。

PyObject *PyArray_Flatten(PyArrayObject *self, NPY_ORDER order)#

相当于 `ndarray.flatten` (*self*, *order*)。返回数组的一维副本。如果 `order` 是 `NPY_FORTRANORDER`,则元素以 Fortran 顺序扫描(第一个维度变化最快)。如果 `order` 是 `NPY_CORDER`,则以 C 顺序扫描 `self` 的元素(最后一个维度变化最快)。如果 `order` 是 `NPY_ANYORDER`,则使用 `PyArray_ISFORTRAN` (*self*) 的结果来确定展平的顺序。

PyObject *PyArray_Ravel(PyArrayObject *self, NPY_ORDER order)#

相当于 self.ravel(order)。基本功能与 PyArray_Flatten(self, order) 相同,但如果 order 为 0 且 self 是 C 风格连续的,则会改变形状但不会执行复制。

条目选择与操作#

PyObject *PyArray_TakeFrom(PyArrayObject *self, PyObject *indices, int axis, PyArrayObject *ret, NPY_CLIPMODE clipmode)#

相当于 ndarray.take (self, indices, axis, ret, clipmode),只是 Python 中的 axis = None 在 C 中通过将 axis 设置为 NPY_MAXDIMS 来实现。根据给定的 axis,从 self 中提取由整数值 indices 指示的项。clipmode 参数可以是 NPY_RAISENPY_WRAPNPY_CLIP,以指示如何处理越界索引。ret 参数可以指定一个输出数组,而不是在内部创建一个。

PyObject *PyArray_PutTo(PyArrayObject *self, PyObject *values, PyObject *indices, NPY_CLIPMODE clipmode)#

相当于 self.put(values, indices, clipmode )。将 values 放入 self 中对应的(展平的)indices 位置。如果 values 太小,它将根据需要重复。

PyObject *PyArray_PutMask(PyArrayObject *self, PyObject *values, PyObject *mask)#

mask 中对应位置(使用展平的上下文)为 true 的地方,将 values 放入 self 中。maskself 数组必须具有相同数量的总元素。如果 values 太小,它将根据需要重复。

PyObject *PyArray_Repeat(PyArrayObject *self, PyObject *op, int axis)#

相当于 ndarray.repeat (self, op, axis)。沿给定 axisself 的元素复制 op 次。op 可以是标量整数,也可以是长度为 self ->dimensions[axis] 的序列,指示沿轴重复每个元素的次数。

PyObject *PyArray_Choose(PyArrayObject *self, PyObject *op, PyArrayObject *ret, NPY_CLIPMODE clipmode)#

相当于 ndarray.choose (self, op, ret, clipmode)。根据 op 中的数组序列中的元素,以及 self 中的整数值,创建一个新数组。数组必须都能广播到相同的形状,并且 self 中的条目应介于 0 和 len(op) 之间。输出放置在 ret 中,除非它为 NULL,在这种情况下,将创建新的输出。clipmode 参数确定了 self 中的条目不在 0 和 len(op) 之间时的行为。

NPY_RAISE#

引发一个 ValueError;

NPY_WRAP#

将小于 0 的值通过加上 len(op) 来包装,并将大于等于 len(op) 的值通过减去 len(op) 来包装,直到它们在范围内;

NPY_CLIP#

所有值都被裁剪到 [0, len(op) ) 区域。

PyObject *PyArray_Sort(PyArrayObject *self, int axis, NPY_SORTKIND kind)#

返回一个数组,其中包含沿 axis 排序的 self 的项。数组的排序使用一种算法,该算法的属性由 kind 指定,kind 是一个整数/枚举,用于指定所使用的排序算法的要求。如果 self* ->descr 是定义了字段的数据类型,则使用 self->descr->names 来确定排序顺序。如果第一个字段相等,则使用第二个字段,依此类推。要更改结构化数组的排序顺序,请创建一个具有不同名称顺序的新数据类型,并使用该新数据类型构造该数组的视图。

这是 ndarray 方法 ndarray.sort 调用时的 C 级函数,尽管 kind 的含义不同——请参阅下面的 NPY_SORTKIND

PyObject *PyArray_ArgSort(PyArrayObject *self, int axis, NPY_SORTKIND kind)#

返回一个索引数组,通过沿给定 axis 选择这些索引,可以得到 self 的排序版本。数组的排序使用一种算法,其属性由 kind 指定,kind 是一个整数/枚举,用于指定所使用的排序算法的要求。如果 self->descr 是定义了字段的数据类型,则使用 self->descr->names 来确定排序顺序。如果第一个字段相等,则使用第二个字段,依此类推。要更改结构化数组的排序顺序,请创建一个具有不同名称顺序的新数据类型,并使用该新数据类型构造该数组的视图。

这是 ndarray 方法 ndarray.argsort 调用时的 C 级函数,尽管 kind 的含义不同——请参阅下面的 NPY_SORTKIND

PyObject *PyArray_LexSort(PyObject *sort_keys, int axis)#

给定一个具有相同形状的数组序列 (sort_keys),返回一个索引数组(类似于 PyArray_ArgSort(…)),该数组将按字典顺序对这些数组进行排序。字典排序指定当两个键相等时,顺序基于后续键的比较。需要一种合并排序(它会保持相等项不动)来为类型定义。排序是通过先使用第一个 sort_key 对索引进行排序,然后使用第二个 sort_key 等等来实现的。这等同于 lexsort(sort_keys, axis) Python 命令。由于合并排序的工作方式,请确保理解 sort_keys 的顺序(与比较两个元素时使用的顺序相反)。

如果这些数组都收集在一个结构化数组中,那么 PyArray_Sort(…) 也可以直接用于对数组进行排序。

PyObject *PyArray_SearchSorted(PyArrayObject *self, PyObject *values, NPY_SEARCHSIDE side, PyObject *perm)#

相当于 ndarray.searchsorted (self, values, side, perm)。假设 self 是一个升序的 1-d 数组,则输出是一个与 values 形状相同的数组,其中如果将 values 中的元素插入到索引之前,self 的顺序将得以保留。不检查 self 是否是升序的。

side 参数指示返回的索引应该是第一个合适的位置(如果为 NPY_SEARCHLEFT)还是最后一个(如果为 NPY_SEARCHRIGHT)。

sorter 参数(如果不是 NULL)必须是一个与 self 长度相同的 1D 整数索引数组,该数组将 self 排序为升序。这通常是调用 PyArray_ArgSort(…) 的结果。使用二分查找来找到所需的插入点。

int PyArray_Partition(PyArrayObject *self, PyArrayObject *ktharray, int axis, NPY_SELECTKIND which)#

相当于 ndarray.partition (self, ktharray, axis, kind)。对数组进行分区,使得由 ktharray 索引的元素处于该元素在完全排序的数组中所处的位置,并将所有小于第 k 个元素的值放在其前面,所有等于或大于第 k 个元素的值放在其后面。所有元素在分区内的顺序是不确定的。如果 self->descr 是一个定义了字段的数据类型,则使用 self->descr->names 来确定排序顺序。第一个字段相等时,第二个字段将用于比较,依此类推。要更改结构化数组的排序顺序,请创建一个具有不同名称顺序的新数据类型,并使用该新数据类型构造该数组的视图。成功返回零,失败返回 -1。

PyObject *PyArray_ArgPartition(PyArrayObject *op, PyArrayObject *ktharray, int axis, NPY_SELECTKIND which)#

相当于 ndarray.argpartition (self, ktharray, axis, kind)。返回一个索引数组,通过沿给定 axis 选择这些索引,可以得到 self 的分区版本。

PyObject *PyArray_Diagonal(PyArrayObject *self, int offset, int axis1, int axis2)#

相当于 ndarray.diagonal (self, offset, axis1, axis2 )。返回由 axis1axis2 定义的 2-d 数组的 offset 对角线。

npy_intp PyArray_CountNonzero(PyArrayObject *self)#

计算数组对象 self 中非零元素的数量。

PyObject *PyArray_Nonzero(PyArrayObject *self)#

相当于 ndarray.nonzero (self)。返回一个索引数组元组,该元组选择 self 中非零的元素。如果 (nd= PyArray_NDIM ( self ))==1,则返回单个索引数组。索引数组的数据类型为 NPY_INTP。如果返回元组 (nd \(\neq\) 1),则其长度为 nd。

PyObject *PyArray_Compress(PyArrayObject *self, PyObject *condition, int axis, PyArrayObject *out)#

相当于 ndarray.compress (self, condition, axis )。返回沿 axis 对应的 condition 中为 true 的元素。

计算#

提示

NPY_RAVEL_AXIS 传递给 axis 以达到与在 Python 中传递 axis=None (将数组视为 1-d 数组) 相同效果。

注意

out 参数指定结果放置的位置。如果 out 为 NULL,则创建输出数组,否则输出将放置在 out 中,out 必须具有正确的尺寸和类型。即使 out 不为 NULL,也会始终返回输出数组的新引用。调用例程者负责在 out 不为 NULL 时对其调用 Py_DECREF,否则将发生内存泄漏。

PyObject *PyArray_ArgMax(PyArrayObject *self, int axis, PyArrayObject *out)#

相当于 ndarray.argmax (self, axis)。返回 self 沿 axis 的最大元素的索引。

PyObject *PyArray_ArgMin(PyArrayObject *self, int axis, PyArrayObject *out)#

相当于 ndarray.argmin (self, axis)。返回 self 沿 axis 的最小元素的索引。

PyObject *PyArray_Max(PyArrayObject *self, int axis, PyArrayObject *out)#

相当于 ndarray.max (self, axis)。返回 self 沿给定 axis 的最大元素。当结果是单个元素时,返回一个 numpy 标量而不是 ndarray。

PyObject *PyArray_Min(PyArrayObject *self, int axis, PyArrayObject *out)#

相当于 ndarray.min (self, axis)。返回 self 沿给定 axis 的最小元素。当结果是单个元素时,返回一个 numpy 标量而不是 ndarray。

PyObject *PyArray_Ptp(PyArrayObject *self, int axis, PyArrayObject *out)#

返回 self 沿 axis 的最大元素与 self 沿 axis 的最小元素之差。当结果是单个元素时,返回一个 numpy 标量而不是 ndarray。

注意

rtype 参数指定了归约运算应在哪个数据类型上进行。如果数组的数据类型不够“大”以处理输出,这一点很重要。默认情况下,所有整数数据类型至少被扩大到 NPY_LONG,以用于“add”和“multiply”通用函数(它们构成了 mean、sum、cumsum、prod 和 cumprod 函数的基础)。

PyObject *PyArray_Mean(PyArrayObject *self, int axis, int rtype, PyArrayObject *out)#

相当于 ndarray.mean (self, axis, rtype)。返回沿给定 axis 的元素的平均值,使用枚举类型 rtype 作为求和的数据类型。使用 NPY_NOTYPE 作为 rtype 可获得默认的求和行为。

PyObject *PyArray_Trace(PyArrayObject *self, int offset, int axis1, int axis2, int rtype, PyArrayObject *out)#

Equivalent to ndarray.trace (self, offset, axis1, axis2, rtype)。返回由axis1axis2变量定义的二维数组的offset对角线元素的总和(使用rtype作为求和的数据类型)。正的offset选择主对角线上方的对角线。负的offset选择主对角线以下的对角线。

PyObject *PyArray_Clip(PyArrayObject *self, PyObject *min, PyObject *max)#

Equivalent to ndarray.clip (self, min, max)。裁剪数组self,使大于max的值被固定为max,小于min的值被固定为min

PyObject *PyArray_Conjugate(PyArrayObject *self, PyArrayObject *out)#

Equivalent to ndarray.conjugate (self)。返回self的复共轭。如果self不是复数数据类型,则返回self的引用。

参数:
  • self – 输入数组。

  • out – 输出数组。如果提供了out,则结果将放入该数组中。

返回:

self 的复共轭。

PyObject *PyArray_Round(PyArrayObject *self, int decimals, PyArrayObject *out)#

Equivalent to ndarray.round (self, decimals, out)。返回将元素舍入到最近小数点位置的数组。小数点位置由 \(10^{-\textrm{decimals}}\) 位定义,因此负的decimals会导致舍入到最近的10、100等。如果outNULL,则创建输出数组;否则,将输出放入out中,out必须具有正确的尺寸和类型。

PyObject *PyArray_Std(PyArrayObject *self, int axis, int rtype, PyArrayObject *out)#

Equivalent to ndarray.std (self, axis, rtype)。返回沿axis的数据的标准差,并将数据转换为rtype类型。

PyObject *PyArray_Sum(PyArrayObject *self, int axis, int rtype, PyArrayObject *out)#

Equivalent to ndarray.sum (self, axis, rtype)。返回self中沿axis的元素的1维向量和。在将数据转换为rtype数据类型后执行求和。

PyObject *PyArray_CumSum(PyArrayObject *self, int axis, int rtype, PyArrayObject *out)#

Equivalent to ndarray.cumsum (self, axis, rtype)。返回self中沿axis的元素的累积1维和。在将数据转换为rtype数据类型后执行求和。

PyObject *PyArray_Prod(PyArrayObject *self, int axis, int rtype, PyArrayObject *out)#

Equivalent to ndarray.prod (self, axis, rtype)。返回self中沿axis的元素的1维积。在将数据转换为rtype数据类型后执行乘积。

PyObject *PyArray_CumProd(PyArrayObject *self, int axis, int rtype, PyArrayObject *out)#

Equivalent to ndarray.cumprod (self, axis, rtype)。返回self中沿axis的元素的累积1维积。在将数据转换为rtype数据类型后执行乘积。

PyObject *PyArray_All(PyArrayObject *self, int axis, PyArrayObject *out)#

Equivalent to ndarray.all (self, axis)。返回一个数组,其中所有元素为True,表示self中由axis定义的每个一维子数组中的所有元素都为True。

PyObject *PyArray_Any(PyArrayObject *self, int axis, PyArrayObject *out)#

Equivalent to ndarray.any (self, axis)。返回一个数组,其中至少有一个元素为True,表示self中由axis定义的每个一维子数组中至少有一个元素为True。

函数#

数组函数#

int PyArray_AsCArray(PyObject **op, void *ptr, npy_intp *dims, int nd, PyArray_Descr *typedescr)#

有时访问多维数组作为C风格的多维数组会很有用,这样就可以使用C的a[i][j][k]语法来实现算法。这个例程返回一个指针ptr,它模拟了1维、2维和3维ndarrays的这种C风格数组。

参数:
  • op – 任何Python对象的地址。此Python对象将被替换为一个等效的、行为良好、C风格连续的ndarray,数据类型由最后两个参数指定。请确保以这种方式窃取输入对象的引用是合理的。

  • ptr – 指向(ctype* for 1-d, ctype** for 2-d or ctype*** for 3-d)变量的地址,其中ctype是数据类型的等效C类型。返回时,ptr将可寻址为1维、2维或3维数组。

  • dims – 一个包含数组对象形状的输出数组。此数组为任何可能发生的循环提供了边界。

  • nd – 数组的维度(1、2或3)。

  • typedescr – 一个 PyArray_Descr 结构,指示所需的数据类型(包括必需的字节序)。该调用将窃取对该参数的引用。

注意

对2维和3维数组的C风格数组模拟并不完整。例如,模拟的指针数组不能传递给期望特定、静态定义的2维和3维数组的子例程。要传递给需要此类输入的函数,必须静态定义所需的数组并复制数据。

int PyArray_Free(PyObject *op, void *ptr)#

必须使用从 PyArray_AsCArray (…)返回的相同对象和内存位置调用此函数。此函数清理否则会泄露的内存。

PyObject *PyArray_Concatenate(PyObject *obj, int axis)#

obj中的对象序列沿axis连接成一个单一的数组。如果维度或类型不兼容,则会引发错误。

PyObject *PyArray_InnerProduct(PyObject *obj1, PyObject *obj2)#

计算obj1obj2的最后维度的积和。两个数组都不会被共轭。

PyObject *PyArray_MatrixProduct(PyObject *obj1, PyObject *obj)#

计算obj1的最后维度和obj2的倒数第二个维度的积和。对于2维数组,这是矩阵乘积。两个数组都不会被共轭。

PyObject *PyArray_MatrixProduct2(PyObject *obj1, PyObject *obj, PyArrayObject *out)#

与PyArray_MatrixProduct相同,但将结果存储在out中。输出数组必须具有正确的形状、类型并且是C连续的,否则将引发异常。

PyArrayObject *PyArray_EinsteinSum(char *subscripts, npy_intp nop, PyArrayObject **op_in, PyArray_Descr *dtype, NPY_ORDER order, NPY_CASTING casting, PyArrayObject *out)#

将提供的数组操作数应用爱因斯坦求和约定,返回一个新数组或将结果放入out中。subscripts中的字符串是索引字母的逗号分隔列表。操作数数量在nop中,op_in是包含这些操作数的数组。可以通过dtype强制输出的数据类型,可以通过order强制输出的顺序(推荐NPY_KEEPORDER),当指定dtype时,casting指示数据转换的严格程度。

有关更多详细信息,请参阅 einsum 函数。

PyObject *PyArray_Correlate(PyObject *op1, PyObject *op2, int mode)#

计算1维数组op1op2的1维相关性。相关性在每个输出点通过将op1op2的移位版本相乘并对结果求和来计算。由于移位,op1op2定义范围之外的所需值被解释为零。mode决定返回多少个移位:0 - 只返回未需要假设零值的移位;1 - 返回一个与op1大小相同的对象;2 - 返回所有可能的移位(接受任何重叠)。

备注

这不计算常规的相关性:如果op2比op1大,则交换参数,并且对于复数数组,共轭永远不会被取。有关信号处理的常规相关性,请参阅PyArray_Correlate2。

PyObject *PyArray_Correlate2(PyObject *op1, PyObject *op2, int mode)#

PyArray_Correlate的更新版本,它使用1维数组的常规相关性定义。相关性在每个输出点通过将op1op2的移位版本相乘并对结果求和来计算。由于移位,op1op2定义范围之外的所需值被解释为零。mode决定返回多少个移位:0 - 只返回未需要假设零值的移位;1 - 返回一个与op1大小相同的对象;2 - 返回所有可能的移位(接受任何重叠)。

备注

计算z如下

z[k] = sum_n op1[n] * conj(op2[n+k])
PyObject *PyArray_Where(PyObject *condition, PyObject *x, PyObject *y)#

如果xy都为NULL,则返回 PyArray_Nonzero (condition)。否则,必须同时提供xy,返回的对象形状与condition相同,并且当condition分别为True或False时,其元素来自xy

其他函数#

npy_bool PyArray_CheckStrides(int elsize, int nd, npy_intp numbytes, npy_intp const *dims, npy_intp const *newstrides)#

确定newstrides是否是一个与具有形状dims和元素大小elsizend维数组的内存一致的跨度数组。检查newstrides数组,看通过每个方向上的给定字节数进行跳转是否会超过numbytes(假设可用内存段的大小)。如果numbytes为0,则假定nddimselsize引用单个段数组,并计算等效的numbytes。如果newstrides可接受,则返回NPY_TRUE;否则返回NPY_FALSE

npy_intp PyArray_MultiplyList(npy_intp const *seq, int n)#
int PyArray_MultiplyIntList(int const *seq, int n)#

这两个例程都将一个n长度的整数数组seq相乘并返回结果。不执行溢出检查。

int PyArray_CompareLists(npy_intp const *l1, npy_intp const *l2, int n)#

给定两个n长度的整数数组l1l2,如果列表相同则返回1;否则返回0。

具有对象语义的辅助数据#

type NpyAuxData#

在使用像结构体 dtype 这样由其他 dtype 组成的更复杂的 dtype 时,创建操作 dtype 的内部循环需要携带额外的数据。NumPy 通过结构体 NpyAuxData 来支持这个想法,并规定了一些约定,以便能够做到这一点。

定义一个 NpyAuxData 类似于在 C++ 中定义一个类,但由于 API 是 C 语言的,对象语义必须手动跟踪。下面是一个函数示例,该函数使用一个元素复制器函数作为原始操作来加倍一个元素。

typedef struct {
    NpyAuxData base;
    ElementCopier_Func *func;
    NpyAuxData *funcdata;
} eldoubler_aux_data;

void free_element_doubler_aux_data(NpyAuxData *data)
{
    eldoubler_aux_data *d = (eldoubler_aux_data *)data;
    /* Free the memory owned by this auxdata */
    NPY_AUXDATA_FREE(d->funcdata);
    PyArray_free(d);
}

NpyAuxData *clone_element_doubler_aux_data(NpyAuxData *data)
{
    eldoubler_aux_data *ret = PyArray_malloc(sizeof(eldoubler_aux_data));
    if (ret == NULL) {
        return NULL;
    }

    /* Raw copy of all data */
    memcpy(ret, data, sizeof(eldoubler_aux_data));

    /* Fix up the owned auxdata so we have our own copy */
    ret->funcdata = NPY_AUXDATA_CLONE(ret->funcdata);
    if (ret->funcdata == NULL) {
        PyArray_free(ret);
        return NULL;
    }

    return (NpyAuxData *)ret;
}

NpyAuxData *create_element_doubler_aux_data(
                            ElementCopier_Func *func,
                            NpyAuxData *funcdata)
{
    eldoubler_aux_data *ret = PyArray_malloc(sizeof(eldoubler_aux_data));
    if (ret == NULL) {
        PyErr_NoMemory();
        return NULL;
    }
    memset(&ret, 0, sizeof(eldoubler_aux_data));
    ret->base->free = &free_element_doubler_aux_data;
    ret->base->clone = &clone_element_doubler_aux_data;
    ret->func = func;
    ret->funcdata = funcdata;

    return (NpyAuxData *)ret;
}
type NpyAuxData_FreeFunc#

NpyAuxData 释放函数的函数指针类型。

type NpyAuxData_CloneFunc#

NpyAuxData 克隆函数的函数指针类型。这些函数在出错时永远不应设置 Python 异常,因为它们可能从多线程上下文中调用。

void NPY_AUXDATA_FREE(NpyAuxData *auxdata)#

一个宏,它适当地调用 auxdata 的释放函数,如果 auxdata 为 NULL 则不做任何操作。

NpyAuxData *NPY_AUXDATA_CLONE(NpyAuxData *auxdata)#

一个宏,它适当地调用 auxdata 的克隆函数,返回辅助数据的深层副本。

数组迭代器#

从 NumPy 1.6.0 开始,这些数组迭代器已被新的数组迭代器 NpyIter 取代。

数组迭代器是一种快速高效地访问 N 维数组元素的简单方法,正如 示例 中所示,该示例提供了更多关于从 C 语言循环遍历数组的这种有用方法的描述。

PyObject *PyArray_IterNew(PyObject *arr)#

从数组 arr 返回一个数组迭代器对象。这等同于 arr.flat。数组迭代器对象可以轻松地以 C 语言风格连续的方式循环遍历 N 维非连续数组。

PyObject *PyArray_IterAllButAxis(PyObject *arr, int *axis)#

返回一个数组迭代器,它将迭代除 *axis 指定的轴之外的所有轴。返回的迭代器不能与 PyArray_ITER_GOTO1D 一起使用。此迭代器可用于编写类似于 ufuncs 的内容,其中对最大轴的循环由单独的子例程完成。如果 *axis 为负,则 *axis 将设置为具有最小步幅的轴,并将使用该轴。

PyObject *PyArray_BroadcastToShape(PyObject *arr, npy_intp const *dimensions, int nd)#

返回一个数组迭代器,该迭代器被广播以作为由 dimensionsnd 提供的形状的数组进行迭代。

int PyArrayIter_Check(PyObject *op)#

如果 op 是数组迭代器(或数组迭代器类型的子类实例),则计算为真。

void PyArray_ITER_RESET(PyObject *iterator)#

iterator 重置到数组的开头。

void PyArray_ITER_NEXT(PyObject *iterator)#

iterator 的索引和 dataptr 成员递增,使其指向数组的下一个元素。如果数组不是(C 风格)连续的,则也递增 N 维坐标数组。

void *PyArray_ITER_DATA(PyObject *iterator)#

指向数组当前元素的指针。

void PyArray_ITER_GOTO(PyObject *iterator, npy_intp *destination)#

iterator 的索引、dataptr 和坐标成员设置为由 N 维 c 数组 destination 指示的数组位置,destination 的大小至少应为 iterator ->nd_m1+1。

void PyArray_ITER_GOTO1D(PyObject *iterator, npy_intp index)#

iterator 的索引和 dataptr 设置为由整数 index 指示的数组位置,index 指向 C 风格扁平化数组中的一个元素。

int PyArray_ITER_NOTDONE(PyObject *iterator)#

只要迭代器还没有遍历完所有元素,就计算为 TRUE,否则计算为 FALSE。

广播(多迭代器)#

PyObject *PyArray_MultiIterNew(int num, ...)#

广播的简化接口。此函数接受要广播的数组数量,然后是 num 个额外的( PyObject * )参数。这些参数被转换为数组并创建迭代器。然后对生成的 multi-iterator 对象调用 PyArray_Broadcast。然后返回生成的、广播的多迭代器对象。然后可以使用单个循环并使用 PyArray_MultiIter_NEXT (...) 来执行广播操作。

void PyArray_MultiIter_RESET(PyObject *multi)#

在多迭代器对象 multi 中,将所有迭代器重置到开头。

void PyArray_MultiIter_NEXT(PyObject *multi)#

将多迭代器对象 multi 中的每个迭代器推进到其下一个(广播的)元素。

void *PyArray_MultiIter_DATA(PyObject *multi, int i)#

返回多迭代器对象中第 i 个迭代器的数据指针。

void PyArray_MultiIter_NEXTi(PyObject *multi, int i)#

只推进第 i 个迭代器的指针。

void PyArray_MultiIter_GOTO(PyObject *multi, npy_intp *destination)#

将多迭代器对象 multi 中的每个迭代器推进到由 N 维 destination 指示的位置,其中 N 是广播数组中的维度数。

void PyArray_MultiIter_GOTO1D(PyObject *multi, npy_intp index)#

将多迭代器对象 multi 中的每个迭代器推进到扁平化广播数组中由 index 指示的相应位置。

int PyArray_MultiIter_NOTDONE(PyObject *multi)#

只要多迭代器还没有遍历完所有(广播结果的)元素,就计算为 TRUE,否则计算为 FALSE。

npy_intp PyArray_MultiIter_SIZE(PyArrayMultiIterObject *multi)#

版本 1.26.0 中新增。

返回多迭代器对象的总广播大小。

int PyArray_MultiIter_NDIM(PyArrayMultiIterObject *multi)#

版本 1.26.0 中新增。

返回多迭代器对象的广播结果的维度数。

npy_intp *PyArray_MultiIter_INDEX(PyArrayMultiIterObject *multi)#

版本 1.26.0 中新增。

返回多迭代器对象的广播结果的当前(1D)索引。

int PyArray_MultiIter_NUMITER(PyArrayMultiIterObject *multi)#

版本 1.26.0 中新增。

返回由多迭代器对象表示的迭代器数量。

void **PyArray_MultiIter_ITERS(PyArrayMultiIterObject *multi)#

版本 1.26.0 中新增。

返回一个迭代器对象数组,该数组包含要一起广播的数组的迭代器。返回时,迭代器将针对广播进行调整。

npy_intp *PyArray_MultiIter_DIMS(PyArrayMultiIterObject *multi)#

版本 1.26.0 中新增。

返回指向多迭代器对象的广播结果的维度/形状的指针。

int PyArray_Broadcast(PyArrayMultiIterObject *mit)#

此函数封装了广播规则。mit 容器应已包含所有需要广播的数组的迭代器。返回时,这些迭代器将进行调整,以便同时迭代每个数组可以实现广播。如果发生错误,则返回负数。

int PyArray_RemoveSmallest(PyArrayMultiIterObject *mit)#

此函数接受一个先前已“广播”的多迭代器对象,找到广播结果中“步幅总和”最小的维度,并调整所有迭代器,使其不遍历该维度(通过使其在该维度上的长度有效为 1)。相应维度将被返回,除非 mit ->nd 为 0,此时返回 -1。此函数对于构造 ufunc 类例程很有用,这些例程正确广播其输入,然后将该例程的 strided 1-d 版本作为内部循环调用。此 1-d 版本通常针对速度进行了优化,因此循环应在不需要大步幅跳转的轴上执行。

邻域迭代器#

邻域迭代器是迭代器对象的子类,可用于迭代某点的邻域。例如,您可能希望迭代 3d 图像的每个体素,并且对于每个体素,迭代一个超立方体。邻域迭代器会自动处理边界,从而使此类代码比手动处理边界更容易编写,但会带来少量开销。

PyObject *PyArray_NeighborhoodIterNew(PyArrayIterObject *iter, npy_intp bounds, int mode, PyArrayObject *fill_value)#

此函数从现有迭代器创建一个新的邻域迭代器。邻域将相对于 iter 当前指向的位置计算,bounds 定义邻域迭代器的形状,mode 参数定义边界处理模式。

bounds 参数应为 (2 * iter->ao->nd) 数组,例如范围 bound[2*i]->bounds[2*i+1] 定义了维度 i 的遍历范围(两个边界都包含在遍历的坐标中)。边界应按每个维度排序(bounds[2*i] <= bounds[2*i+1])。

模式应为以下之一:

NPY_NEIGHBORHOOD_ITER_ZERO_PADDING#

零填充。边界外的值将为 0。

NPY_NEIGHBORHOOD_ITER_ONE_PADDING#

一填充。边界外的值将为 1。

NPY_NEIGHBORHOOD_ITER_CONSTANT_PADDING#

常量填充。边界外的值将与 fill_value 中的第一个项相同。

NPY_NEIGHBORHOOD_ITER_MIRROR_PADDING#

镜像填充。边界外的值将如同数组项被镜像一样。例如,对于数组 [1, 2, 3, 4],x[-2] 将为 2,x[-2] 将为 1,x[4] 将为 4,x[5] 将为 1,依此类推。

NPY_NEIGHBORHOOD_ITER_CIRCULAR_PADDING#

循环填充。边界外的值将如同数组被重复一样。例如,对于数组 [1, 2, 3, 4],x[-2] 将为 3,x[-2] 将为 4,x[4] 将为 1,x[5] 将为 2,依此类推。

如果模式是常量填充(NPY_NEIGHBORHOOD_ITER_CONSTANT_PADDING),fill_value 应指向一个包含填充值的数组对象(如果数组包含多个项,则第一个项是填充值)。对于其他情况,fill_value 可以为 NULL。

  • 该迭代器持有 iter 的引用。

  • 失败时返回 NULL(此时 iter 的引用计数不变)。

  • iter 本身可以是一个邻域迭代器:这对于例如自动边界处理很有用。

  • 从此函数返回的对象可以安全地用作普通迭代器。

  • 如果 iter 的位置发生更改,任何后续调用 PyArrayNeighborhoodIter_Next 的行为都是未定义的,并且必须调用 PyArrayNeighborhoodIter_Reset。

  • 如果 iter 的位置不是数据开头,并且 iter 的底层数据是连续的,则迭代器将指向数据的开头而不是 iter 指向的位置。为避免这种情况,应在创建迭代器后才将 iter 移动到所需位置,并且必须调用 PyArrayNeighborhoodIter_Reset。

PyArrayIterObject *iter;
PyArrayNeighborhoodIterObject *neigh_iter;
iter = PyArray_IterNew(x);

/*For a 3x3 kernel */
bounds = {-1, 1, -1, 1};
neigh_iter = (PyArrayNeighborhoodIterObject*)PyArray_NeighborhoodIterNew(
     iter, bounds, NPY_NEIGHBORHOOD_ITER_ZERO_PADDING, NULL);

for(i = 0; i < iter->size; ++i) {
     for (j = 0; j < neigh_iter->size; ++j) {
             /* Walk around the item currently pointed by iter->dataptr */
             PyArrayNeighborhoodIter_Next(neigh_iter);
     }

     /* Move to the next point of iter */
     PyArrayIter_Next(iter);
     PyArrayNeighborhoodIter_Reset(neigh_iter);
}
int PyArrayNeighborhoodIter_Reset(PyArrayNeighborhoodIterObject *iter)#

将迭代器位置重置为邻域的第一个点。每当 PyArray_NeighborhoodIterObject 中提供的 iter 参数发生更改时,都应调用此函数(参见示例)。

int PyArrayNeighborhoodIter_Next(PyArrayNeighborhoodIterObject *iter)#

调用此函数后,iter->dataptr 指向邻域的下一个点。在访问完邻域的每个点后调用此函数是未定义的。

数组标量#

PyObject *PyArray_Return(PyArrayObject *arr)#

此函数窃取 arr 的引用。

此函数检查 arr 是否为 0 维数组,如果是,则返回相应的数组标量。只要可能将 0 维数组返回给 Python,就应使用此函数。

PyObject *PyArray_Scalar(void *data, PyArray_Descr *dtype, PyObject *base)#

返回一个给定dtype的数组标量对象,该对象从data指向的内存中复制而来。base应该是数据所有者的数组对象。如果dtypevoid标量,或者设置了NPY_USE_GETITEM标志并且已知getitem方法使用了arr参数而未检查其是否为NULL,则需要base。否则base可以为NULL

如果数据不是本机字节序(由dtype->byteorder指示),则此函数将字节交换数据,因为数组标量始终是正确的机器字节序。

PyObject *PyArray_ToScalar(void *data, PyArrayObject *arr)#

返回一个数组标量对象,其类型和项大小由数组对象arr指示,从data指向的内存复制而来,并在arr中的数据不是机器字节序时进行交换。

PyObject *PyArray_FromScalar(PyObject *scalar, PyArray_Descr *outcode)#

scalar(应为一个数组标量对象)返回一个由outcode确定的0维数组。如果outcode为NULL,则类型由scalar确定。

void PyArray_ScalarAsCtype(PyObject *scalar, void *ctypeptr)#

将数组标量中的实际值通过指针ctypeptr返回。没有错误检查,因此scalar必须是数组标量对象,并且ctypeptr必须有足够的空间来容纳正确类型。对于灵活大小的类型,数据指针将被复制到ctypeptr指向的内存中;对于其他所有类型,实际数据将被复制到ctypeptr指向的地址。

int PyArray_CastScalarToCtype(PyObject *scalar, void *ctypeptr, PyArray_Descr *outcode)#

将数组标量scalar中的数据(强制转换为由outcode指示的数据类型)放入ctypeptr指向的内存中(该内存必须足够大以容纳传入的数据)。

成功返回0,失败返回-1。

PyObject *PyArray_TypeObjectFromType(int type)#

根据类型编号type返回一个标量类型对象。等同于PyArray_DescrFromType(type)->typeobj,但对引用计数和错误检查有所不同。成功时返回类型对象的引用,失败时返回NULL

NPY_SCALARKIND PyArray_ScalarKind(int typenum, PyArrayObject **arr)#

查询标量值特殊提升的旧方法。NumPy本身不再使用此方法,预计最终将被弃用。

新的DTypes可以定义针对Python标量的提升规则。

int PyArray_CanCoerceScalar(char thistype, char neededtype, NPY_SCALARKIND scalar)#

查询标量值特殊提升的旧方法。NumPy本身不再使用此方法,预计最终将被弃用。

对于类似的目的,请使用PyArray_ResultType

数据类型描述符#

警告

数据类型对象必须是引用计数的,因此请注意不同C-API调用对数据类型引用的操作。标准规则是,当返回数据类型对象时,它是一个新引用。接受PyArray_Descr*对象并返回数组的函数会“窃取”对数据类型输入的引用,除非另有说明。因此,您必须拥有对用作此类函数输入的任何数据类型对象的引用。

int PyArray_DescrCheck(PyObject *obj)#

如果obj是数据类型对象(PyArray_Descr*),则求值为真。

PyArray_Descr *PyArray_DescrNew(PyArray_Descr *obj)#

返回一个从obj复制的新数据类型对象(字段引用仅更新,以便新对象指向同一个字段字典,如果存在)。

PyArray_Descr *PyArray_DescrNewFromType(int typenum)#

根据内置(或用户注册)的数据类型typenum创建一个新的数据类型对象。所有内置类型都不应更改其任何字段。这会创建一个PyArray_Descr结构的副本,以便您可以根据需要进行填充。对于需要新的elsize成员以在数组构造中有意义的灵活数据类型,此函数尤为重要。

PyArray_Descr *PyArray_DescrNewByteorder(PyArray_Descr *obj, char newendian)#

创建具有根据newendian设置的字节序的新数据类型对象。所有引用的数据类型对象(数据类型对象中的subdescrfields成员)也会被更改(递归)。

newendian的值是以下宏之一:

NPY_IGNORE#
NPY_SWAP#
NPY_NATIVE#
NPY_LITTLE#
NPY_BIG#

如果遇到NPY_IGNORE的字节序,则保持不变。如果newendian是NPY_SWAP,则交换所有字节序。其他有效的newendian值是NPY_NATIVENPY_LITTLENPY_BIG,它们都会导致返回的数据类型描述符(及其所有引用的数据类型描述符)具有相应的字节序。

PyArray_Descr *PyArray_DescrFromObject(PyObject *op, PyArray_Descr *mintype)#

根据对象op(应为“嵌套”序列对象)和最小数据类型描述符mintype(可以为NULL)确定合适的数据类型对象。行为类似于array(op).dtype。不要将此函数与PyArray_DescrConverter混淆。此函数基本上会查看(嵌套)序列中的所有对象,并根据找到的元素确定数据类型。

PyArray_Descr *PyArray_DescrFromScalar(PyObject *scalar)#

从数组标量对象返回一个数据类型对象。不进行检查以确保scalar是数组标量。如果无法确定合适的数据类型,则默认返回NPY_OBJECT类型的数据类型。

PyArray_Descr *PyArray_DescrFromType(int typenum)#

返回与typenum对应的数据类型对象。typenum可以是枚举类型之一、枚举类型的字符码,或用户定义的类型。如果要使用可变大小的数组,则需要flexible typenum并设置结果的elsize参数为所需的大小。typenumNPY_TYPES之一。

int PyArray_DescrConverter(PyObject *obj, PyArray_Descr **dtype)#

将任何兼容的Python对象obj转换为dtype中的数据类型对象。大量Python对象可以转换为数据类型对象。有关数据类型对象的完整描述,请参阅数据类型对象(dtype)。此转换器版本将None对象转换为NPY_DEFAULT_TYPE数据类型对象。此函数可用于PyArg_ParseTuple处理中的“O&”字符代码。

int PyArray_DescrConverter2(PyObject *obj, PyArray_Descr **dtype)#

将任何兼容的Python对象obj转换为dtype中的数据类型对象。此转换器版本将None对象转换为NULL返回的数据类型。此函数也可以与PyArg_ParseTuple处理中的“O&”字符一起使用。

int PyArray_DescrAlignConverter(PyObject *obj, PyArray_Descr **dtype)#

PyArray_DescrConverter类似,但它像编译器一样将C结构类似的对齐对象对齐到字边界。

int PyArray_DescrAlignConverter2(PyObject *obj, PyArray_Descr **dtype)#

PyArray_DescrConverter2类似,但它像编译器一样将C结构类似的对齐对象对齐到字边界。

数据类型提升和检查#

PyArray_DTypeMeta *PyArray_CommonDType(const PyArray_DTypeMeta *dtype1, const PyArray_DTypeMeta *dtype2)#

此函数定义了公共DType操作。请注意,公共DType将不会是object(除非其中一个DType是object)。与numpy.result_type类似,但它作用于类而不是实例。

PyArray_DTypeMeta *PyArray_PromoteDTypeSequence(npy_intp length, PyArray_DTypeMeta **dtypes_in)#

促进DTypes列表相互之间的提升,以确保即使更改顺序也能获得稳定的结果。此函数更智能,并且通常能在common_dtype(common_dtype(dt1, dt2), dt3)依赖于操作顺序或失败时,获得成功且无歧义的结果。尽管如此,DTypes应确保其公共DType实现是可交换的(主要是,无符号和有符号整数不是)。

为了保证结果的一致性,DTypes必须“传递性地”实现公共DType。如果A提升B,B提升C,那么A通常也必须提升C;其中“提升”意味着实现提升。(对于抽象DTypes有一些例外)

一般来说,只要最通用的dtype严格更大,或与其他所有dtypes兼容,这种方法总是有效的。例如,将float16与任何其他浮点数、整数或无符号整数进行提升,再次得到一个浮点数。

PyArray_Descr *PyArray_GetDefaultDescr(const PyArray_DTypeMeta *DType)#

给定一个DType类,返回默认实例(描述符)。这首先检查singleton,并且仅在必要时调用default_descr函数。

自定义数据类型#

新增于版本 2.0。

这些函数允许在NumPy之外定义自定义的灵活数据类型。有关新DType系统的原理和设计的更多详细信息,请参阅NEP 42。请参阅numpy-user-dtypes存储库以获取许多示例DTypes。另请参阅PyArray_DTypeMeta和PyArrayDTypeMeta_Spec,了解PyArray_DTypeMetaPyArrayDTypeMeta_Spec的文档。

int PyArrayInitDTypeMeta_FromSpec(PyArray_DTypeMeta *Dtype, PyArrayDTypeMeta_Spec *spec)#

初始化一个新的DType。它目前必须是一个声明为PyArray_DTypeMeta而不是PyTypeObject的静态Python C类型。此外,它必须是np.dtype的子类,并在调用PyType_Ready之前将其类型设置为PyArrayDTypeMeta_Type,它比普通PyTypeObject具有额外的字段。请参阅numpy-user-dtypes存储库中的示例,了解带参数和不带参数数据类型的用法。

标志#

可以在PyArrayDTypeMeta_Spec上设置的标志,用于初始化DType。

NPY_DT_ABSTRACT#

指示DType是DType层次结构中的抽象“基”DType,不应直接实例化。

NPY_DT_PARAMETRIC#

指示DType是参数化的,并且没有唯一的单例实例。

NPY_DT_NUMERIC#

指示DType代表一个数值。

槽ID和API函数类型定义#

这些ID对应于DType API中的槽,并用于标识PyArrayDTypeMeta_Spec结构体的slots数组成员的每个槽的实现。

NPY_DT_discover_descr_from_pyobject#
typedef PyArray_Descr *(PyArrayDTypeMeta_DiscoverDescrFromPyobject)(PyArray_DTypeMeta *cls, PyObject *obj)#

在 DType 推断期间用于查找给定 PyObject 的正确 DType。必须返回一个合适的描述符实例,以便存储传入的 Python 对象中的数据。 obj 是要检查的 Python 对象,cls 是要为其创建描述符的 DType 类。

NPY_DT_default_descr#
typedef PyArray_Descr *(PyArrayDTypeMeta_DefaultDescriptor)(PyArray_DTypeMeta *cls)#

返回 DType 的默认描述符实例。必须为参数化数据类型定义。非参数化数据类型默认返回单例。

NPY_DT_common_dtype#
typedef PyArray_DTypeMeta *(PyArrayDTypeMeta_CommonDType)(PyArray_DTypeMeta *dtype1, PyArray_DTypeMeta *dtype2)#

给定两个输入 DType,确定可以存储这两种类型的值的适当的“通用” DType。如果不存在此类类型,则返回 Py_NotImplemented

NPY_DT_common_instance#
typedef PyArray_Descr *(PyArrayDTypeMeta_CommonInstance)(PyArray_Descr *dtype1, PyArray_Descr *dtype2)#

给定两个输入描述符,确定可以存储这两种实例的值的适当的“通用”描述符。发生错误时返回 NULL

NPY_DT_ensure_canonical#
typedef PyArray_Descr *(PyArrayDTypeMeta_EnsureCanonical)(PyArray_Descr *dtype)#

返回描述符实例的“规范”表示。规范描述符的概念概括了字节顺序的概念,因为规范描述符始终具有本机字节顺序。如果描述符已经是规范的,此函数将返回指向输入描述符的新引用。

NPY_DT_setitem#
typedef int (PyArrayDTypeMeta_SetItem)(PyArray_Descr*, PyObject*, char*)#

在给定 PyObject 的情况下,实现数组元素的标量 setitem。

NPY_DT_getitem#
typedef PyObject *(PyArrayDTypeMeta_GetItem)(PyArray_Descr*, char*)#

实现数组元素的标量 getitem。必须返回 Python 标量。

NPY_DT_get_clear_loop#

如果定义了,则设置一个遍历循环来清除数组中的数据。这对于必须在数组被垃圾回收之前清理数组条目的引用数组特别有用。实现 PyArrayMethod_GetTraverseLoop

NPY_DT_get_fill_zero_loop#

如果定义了,则设置一个遍历循环来用“零”值填充数组,这可能具有 DType 特定的含义。当 numpy.zeros 用于需要写入自定义零值占位符的数组时,如果由于某种原因零填充的数组不足够,则会调用此函数。实现 PyArrayMethod_GetTraverseLoop

NPY_DT_finalize_descr#
typedef PyArray_Descr *(PyArrayDTypeMeta_FinalizeDescriptor)(PyArray_Descr *dtype)#

如果定义了,则是在创建数组后用于“完成”描述符实例的函数。此函数的一个用途是强制新创建的数组使用新创建的描述符实例,而不考虑用户提供的任何输入描述符。

NPY_DT_get_constant#
typedef int (PyArrayDTypeMeta_GetConstant)(PyArray_Descr *descr, int constant_id, void *out)#

如果定义了,则允许 DType 公开常量值,例如机器限制、特殊值(无穷大、NaN)和浮点特性。descr 是描述符实例,constant_idNPY_CONSTANT_* 宏之一,out 是指向未初始化内存的指针,常量值应写入其中。out 指向的内存可能未对齐且未初始化。成功时返回 1,常量不可用时返回 0,错误时返回 -1 并设置错误。

常量 ID:

以下常量 ID 用于检索 dtype 特定值

基本常量(适用于所有数值类型)

NPY_CONSTANT_zero#

dtype 的零值。

NPY_CONSTANT_one#

dtype 的一值。

NPY_CONSTANT_minimum_finite#

dtype 可表示的最小有限值。对于浮点类型,这是最小的负有限值(例如,-FLT_MAX)。

NPY_CONSTANT_maximum_finite#

dtype 可表示的最大有限值。

浮点特殊值:

NPY_CONSTANT_inf#

正无穷大(仅限浮点类型)。

NPY_CONSTANT_ninf#

负无穷大(仅限浮点类型)。

NPY_CONSTANT_nan#

非数字(NaN)(仅限浮点类型)。

浮点特性(dtype 原生类型的值)

NPY_CONSTANT_finfo_radix#

浮点表示的基数。所有浮点类型均为 2。

NPY_CONSTANT_finfo_eps#

机器 epsilon:1.0 与大于 1.0 的下一个可表示值之间的差值。对应于 C 宏,如 FLT_EPSILONDBL_EPSILON

注意

对于 IBM 双精度格式(PowerPC)的 long double,此值为 0x1p-105L (2^-105),基于约 106 位的尾数精度。

NPY_CONSTANT_finfo_epsneg#

1.0 与小于 1.0 的下一个可表示值之间的差值。对于二进制浮点类型,通常为 eps / radix

NPY_CONSTANT_finfo_smallest_normal#

最小的正规化浮点数。对应于 C 宏,如 FLT_MINDBL_MIN。这是尾数中具有最高位 1 的最小可能值。

NPY_CONSTANT_finfo_smallest_subnormal#

最小的正非规化(denormalized)浮点数。对应于 C 宏,如 FLT_TRUE_MINDBL_TRUE_MIN。这是可表示的最小正值,尾数中具有前导 0 位。

浮点特性(整数值,类型为 npy_intp

这些常量返回关于浮点表示的整数元数据。它们带有 1 << 16 位标记,表示它们返回 npy_intp 值而不是 dtype 的原生类型。

NPY_CONSTANT_finfo_nmant#

尾数位数(不包括隐式前导位)。例如,IEEE 754 binary64(双精度)有 52 个显式尾数位,因此此函数返回 52。对应于 C 标准宏中的 MANT_DIG - 1

NPY_CONSTANT_finfo_min_exp#

最小指数值。这是最小的负整数,使得基数的幂(小于该整数 1)是一个正规化浮点数。对应于 C 标准宏中的 MIN_EXP - 1(例如,FLT_MIN_EXP - 1)。

NPY_CONSTANT_finfo_max_exp#

最大指数值。这是最大的正整数,使得基数的幂(小于该整数 1)是一个可表示的有限浮点数。对应于 C 标准宏中的 MAX_EXP(例如,FLT_MAX_EXP)。

NPY_CONSTANT_finfo_decimal_digits#

小数位精度。对应于 C 标准宏中的 DIG(例如,FLT_DIGDBL_DIG)。

PyArray_ArrFuncs 插槽#

除了上述插槽外,还公开了以下插槽,允许填充附加到描述符实例的 PyArray_ArrFuncs 结构。请注意,将来这些将被替换为正确的 DType API 插槽,但目前我们已公开了旧的 PyArray_ArrFuncs 插槽。

NPY_DT_PyArray_ArrFuncs_getitem#

允许设置每个 dtype 的 getitem。请注意,除非使用 NPY_DT_getitem ID 定义的函数被调用,否则不需要定义默认版本。此版本比使用 NPY_DT_getitem 稍快,但有时需要处理 NULL 输入数组。

NPY_DT_PyArray_ArrFuncs_setitem#

允许设置每个 dtype 的 setitem。请注意,除非出于某种原因使用 NPY_DT_setitem ID 定义的函数被调用,否则不需要定义默认版本。

NPY_DT_PyArray_ArrFuncs_compare#

numpy.sort 计算比较,实现 PyArray_CompareFunc

NPY_DT_PyArray_ArrFuncs_argmax#

numpy.argmax 计算 argmax,实现 PyArray_ArgFunc

NPY_DT_PyArray_ArrFuncs_argmin#

numpy.argmin 计算 argmin,实现 PyArray_ArgFunc

NPY_DT_PyArray_ArrFuncs_dotfunc#

numpy.dot 计算点积,实现 PyArray_DotFunc

NPY_DT_PyArray_ArrFuncs_scanfunc#

用于 numpy.fromfile 的格式化输入函数,实现 PyArray_ScanFunc

NPY_DT_PyArray_ArrFuncs_fromstr#

用于 numpy.fromstring 的字符串解析函数,实现 PyArray_FromStrFunc

NPY_DT_PyArray_ArrFuncs_nonzero#

numpy.nonzero 计算 nonzero 函数,实现 PyArray_NonzeroFunc

NPY_DT_PyArray_ArrFuncs_fill#

用于 numpy.ndarray.fill 的数组填充函数,实现 PyArray_FillFunc

NPY_DT_PyArray_ArrFuncs_fillwithscalar#

用于 numpy.ndarray.fill 使用标量值填充数组的函数,实现 PyArray_FillWithScalarFunc

NPY_DT_PyArray_ArrFuncs_sort#

长度为 NPY_NSORTS 的 PyArray_SortFunc 数组。如果设置,则允许为 numpy 实现的每种排序算法定义自定义排序实现。

NPY_DT_PyArray_ArrFuncs_argsort#

长度为 NPY_NSORTS 的 PyArray_ArgSortFunc 数组。如果设置,则允许为 numpy 实现的每种排序算法定义自定义 argsort 实现。

宏和静态内联函数#

提供这些宏和静态内联函数,以便在处理 PyArray_DTypeMeta 实例时允许更易懂和惯用的代码。

NPY_DTYPE(descr)#

返回给定描述符实例的 DType 的 PyArray_DTypeMeta * 指针。

static inline PyArray_DTypeMeta *NPY_DT_NewRef(PyArray_DTypeMeta *o)#

返回 DType 的新引用(PyArray_DTypeMeta * 指针)。

转换实用程序#

PyArg_ParseTuple 使用#

所有这些函数都可以与 PyArg_ParseTuple (...) 一起使用,并带有“O&”格式说明符,以自动将任何 Python 对象转换为所需的 C 对象。所有这些函数在成功时返回 NPY_SUCCEED,在失败时返回 NPY_FAIL。所有这些函数的第一参数都是 Python 对象。第二个参数是要将 Python 对象转换为的 C 类型的**地址**。

警告

请务必了解在使用这些转换函数时应采取哪些步骤来管理内存。这些函数可能需要根据您的使用情况来释放内存和/或更改特定对象的引用计数。

int PyArray_Converter(PyObject *obj, PyObject **address)#

将任何 Python 对象转换为 PyArrayObject。如果 PyArray_Check (obj) 为 TRUE,则会增加其引用计数,并将引用放入 address。如果 obj 不是数组,则使用 PyArray_FromAny 将其转换为数组。无论返回什么,在完成后都必须 DECREF address 中此例程返回的对象。

int PyArray_OutputConverter(PyObject *obj, PyArrayObject **address)#

这是传递给函数的输出数组的默认转换器。如果 objPy_NoneNULL,则 *address 将为 NULL,但调用会成功。如果 PyArray_Check ( obj) 为 TRUE,则在不增加其引用计数的情况下将其返回到 *address 中。

int PyArray_IntpConverter(PyObject *obj, PyArray_Dims *seq)#

将任何维度小于 NPY_MAXDIMS 的 Python 序列 obj 转换为 C 数组 npy_intp。Python 对象也可以是单个数字。seq 变量是指向具有成员 ptr 和 len 的结构的指针。成功返回后,seq ->ptr 指向的内存必须通过调用 PyDimMem_FREE 来释放,以避免内存泄漏。内存大小的限制允许此转换器方便地用于旨在解释为数组形状的序列。

int PyArray_BufferConverter(PyObject *obj, PyArray_Chunk *buf)#

将任何具有(单段)缓冲区接口的 Python 对象 obj 转换为一个结构体变量,该变量详细说明了对象对其内存块的使用。buf 变量是指向具有 base、ptr、len 和 flags 成员的结构的指针。PyArray_Chunk 结构体在二进制上与 Python 的缓冲区对象兼容(在 32 位平台上通过其 len 成员,在 64 位平台上通过其 ptr 成员)。返回时,base 成员设置为 obj(如果 obj 已经是指向另一个对象的缓冲区对象,则设置为其 base)。如果您需要保留内存,请确保增加 base 成员的引用计数。内存块由 buf ->ptr 成员指向,长度为 buf ->len。buf 的 flags 成员是 NPY_ARRAY_ALIGNED,如果 obj 具有可写缓冲区接口,则设置 NPY_ARRAY_WRITEABLE 标志。

int PyArray_AxisConverter(PyObject *obj, int *axis)#

将代表轴参数的 Python 对象 obj 转换为传递给需要整数轴的函数的正确值。具体来说,如果 obj 是 None,则 axis 设置为 NPY_RAVEL_AXIS,这会被接受轴参数的 C-API 函数正确解释。

int PyArray_BoolConverter(PyObject *obj, npy_bool *value)#

将任何 Python 对象 obj 转换为 NPY_TRUENPY_FALSE,并将结果放入 value 中。

int PyArray_ByteorderConverter(PyObject *obj, char *endian)#

将 Python 字符串转换为相应的字节序字符:“>”、“<”、“s”、“=”或“|”。

int PyArray_SortkindConverter(PyObject *obj, NPY_SORTKIND *sort)#

将 Python 字符串转换为 NPY_QUICKSORT(以 'q' 或 'Q' 开头)、NPY_HEAPSORT(以 'h' 或 'H' 开头)、NPY_MERGESORT(以 'm' 或 'M' 开头)或 NPY_STABLESORT(以 't' 或 'T' 开头)之一。为了向后兼容,NPY_MERGESORTNPY_STABLESORT 互为别名,并且可能根据数据类型指向几种稳定的排序算法之一。

int PyArray_SearchsideConverter(PyObject *obj, NPY_SEARCHSIDE *side)#

将 Python 字符串转换为 NPY_SEARCHLEFT(以 'l' 或 'L' 开头)或 NPY_SEARCHRIGHT(以 'r' 或 'R' 开头)之一。

int PyArray_OrderConverter(PyObject *obj, NPY_ORDER *order)#

将 Python 字符串 'C'、'F'、'A' 和 'K' 转换为 NPY_ORDER 枚举 NPY_CORDERNPY_FORTRANORDERNPY_ANYORDERNPY_KEEPORDER

int PyArray_CastingConverter(PyObject *obj, NPY_CASTING *casting)#

将 Python 字符串 'no'、'equiv'、'safe'、'same_kind' 和 'unsafe' 转换为 NPY_CASTING 枚举 NPY_NO_CASTINGNPY_EQUIV_CASTINGNPY_SAFE_CASTINGNPY_SAME_KIND_CASTINGNPY_UNSAFE_CASTING

int PyArray_ClipmodeConverter(PyObject *object, NPY_CLIPMODE *val)#

将 Python 字符串 'clip'、'wrap' 和 'raise' 转换为 NPY_CLIPMODE 枚举 NPY_CLIPNPY_WRAPNPY_RAISE

int PyArray_ConvertClipmodeSequence(PyObject *object, NPY_CLIPMODE *modes, int n)#

将剪裁模式序列或单个剪裁模式转换为 NPY_CLIPMODE 值 C 数组。在调用此函数之前必须知道剪裁模式的数量 n。此函数提供用于帮助函数允许为每个维度设置不同的剪裁模式。

其他转换#

int PyArray_PyIntAsInt(PyObject *op)#

将各种 Python 对象(包括数组和数组标量)转换为标准整数。出错时,返回 -1 并设置异常。您可能会发现宏很有用

#define error_converting(x) (((x) == -1) && PyErr_Occurred())
npy_intp PyArray_PyIntAsIntp(PyObject *op)#

将各种 Python 对象(包括数组和数组标量)转换为(平台指针大小的)整数。出错时,返回 -1 并设置异常。

int PyArray_IntpFromSequence(PyObject *seq, npy_intp *vals, int maxvals)#

将作为 seq 传入的任何 Python 序列(或单个 Python 数字)转换为(最多)maxvals 个指针大小的整数,并将它们放入 vals 数组中。序列可以小于 maxvals,因为返回的是转换对象的数量。

包含和导入 C API#

要使用 NumPy C-API,您通常需要包含 numpy/ndarrayobject.h 头文件,并为一些与 ufunc 相关的 numpy/ufuncobject.h 文件(arrayobject.hndarrayobject.h 的别名)。

这两个头文件导出大多数相关功能。通常,任何使用 NumPy API 的项目都必须使用 PyArray_ImportNumPyAPI()import_array() 函数之一来导入 NumPy。在某些地方,不需要需要 import_array() 的功能,因为您只需要类型定义。在这种情况下,包含 numpy/ndarratypes.h 即可。

对于典型的 Python 项目,多个 C 或 C++ 文件将被编译成单个共享对象(Python C 模块),并且 PyArray_ImportNumPyAPI() 应该在其模块初始化中调用。

当您有一个单一的 C 文件时,它将由

#include "numpy/ndarrayobject.h"

PyMODINIT_FUNC PyInit_my_module(void)
{
    if (PyArray_ImportNumPyAPI() < 0) {
        return NULL;
    }
    /* Other initialization code. */
}

但是,大多数项目将有额外的 C 文件,这些文件都链接到一个 Python 模块中。在这种情况下,辅助 C 文件通常没有规范的位置来调用 PyArray_ImportNumPyAPI(尽管经常调用它并且效率很高)。

为了解决这个问题,NumPy 提供了以下模式,主文件在包含之前被修改以定义 PY_ARRAY_UNIQUE_SYMBOL

/* Main module file */
#define PY_ARRAY_UNIQUE_SYMBOL MyModule
#include "numpy/ndarrayobject.h"

PyMODINIT_FUNC PyInit_my_module(void)
{
    if (PyArray_ImportNumPyAPI() < 0) {
        return NULL;
    }
    /* Other initialization code. */
}

而其他文件使用

/* Second file without any import */
#define NO_IMPORT_ARRAY
#define PY_ARRAY_UNIQUE_SYMBOL MyModule
#include "numpy/ndarrayobject.h"

当然,您可以将这些定义添加到整个项目中使用的本地头文件中。您只需要确保主文件 _不_ 定义 NO_IMPORT_ARRAY

对于 numpy/ufuncobject.h,相同的逻辑适用,但唯一符号机制是 #define PY_UFUNC_UNIQUE_SYMBOL(两者可以匹配)。

此外,您可能希望添加一个 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION 来避免有关可能使用旧 API 的警告。

注意

如果您遇到访问冲突,请确保 NumPy API 已正确导入并且符号 PyArray_API 不是 NULL。在调试器中,此符号的实际名称将是 PY_ARRAY_UNIQUE_SYMBOL``+``PyArray_API,因此例如在上面是 MyModulePyArray_API。(例如,甚至可以在崩溃前执行 printf("%p\n", PyArray_API);。)

机制细节和动态链接#

机制的主要部分是,没有 NumPy 需要为您定义一个 void **PyArray_API 表来查找所有函数。根据您的宏设置,这会根据 NO_IMPORT_ARRAYPY_ARRAY_UNIQUE_SYMBOL 是否已定义来采用不同的路径

  • 如果两者均未定义,则 C-API 被声明为 static void **PyArray_API,因此它仅在编译单元/使用 #include <numpy/arrayobject.h> 的文件中可见。

  • 如果仅定义了 PY_ARRAY_UNIQUE_SYMBOL(它可以为空),则它被声明为非静态的 void **,允许其他链接的文件使用它。

  • 如果定义了 NO_IMPORT_ARRAY,则该表被声明为 extern void **,这意味着它必须链接到一个不使用 NO_IMPORT_ARRAY 的文件。

PY_ARRAY_UNIQUE_SYMBOL 机制另外会更改名称以避免冲突。

在 NumPy 版本: 2.1 中更改了头文件,以避免在单个共享对象/dll 之外共享表(这在 Windows 上始终如此)。有关详细信息,请参阅 NPY_API_SYMBOL_ATTRIBUTE

为了从另一个扩展模块中使用 C-API,必须调用 import_array 函数。如果扩展模块是自包含在一个 .c 文件中,那么这就足够了。然而,如果扩展模块涉及多个需要 C-API 的文件,那么必须采取一些额外的步骤。

int PyArray_ImportNumPyAPI(void)#

确保 NumPy C-API 已导入且可用。它在成功时返回 0,如果 NumPy 无法导入,则返回 -1 并设置错误。虽然最好在模块初始化时调用一次,但如果多次调用此函数,它的开销非常小。

2.0 版本新增: 此函数在 npy_2_compat.h 头文件中向后移植。

import_array(void)#

此函数必须在将使用 C-API 的模块的初始化部分调用。它导入存储函数指针表的模块,并将正确的变量指向它。此宏在错误时包含 return NULL;,因此 PyArray_ImportNumPyAPI() 更适合自定义错误检查。您可能还会看到 _import_array()(一个函数,而不是宏,但如果它失败,您可能希望引发更好的错误)以及 import_array1(ret) 变体的用法,后者自定义返回值。

PY_ARRAY_UNIQUE_SYMBOL#
NPY_API_SYMBOL_ATTRIBUTE#

2.1 版本新增。

一个附加符号,可用于共享例如共享对象边界之外的可见性。默认情况下,NumPy 添加 C 可见性隐藏属性(如果可用):void __attribute__((visibility("hidden"))) **PyArray_API;。您可以通过定义 NPY_API_SYMBOL_ATTRIBUTE 来更改此设置,这将使其变为:void NPY_API_SYMBOL_ATTRIBUTE **PyArray_API;(通过唯一符号进行附加的名称修饰)。

添加一个空的 #define NPY_API_SYMBOL_ATTRIBUTE 将具有与 NumPy 1.x 相同的行为。

注意

Windows 从未具有共享可见性,尽管您可以使用此宏来实现它。我们通常不鼓励在共享边界线之外共享,因为导入数组 API 会包括 NumPy 版本检查。

NO_IMPORT_ARRAY#

ndarrayobject.h 包含之前定义 NO_IMPORT_ARRAY 表示 NumPy C API 导入在另一个文件中处理,并且包含机制不会在此处添加。您必须有一个不定义 NO_IMPORT_ARRAY 的文件。

#define PY_ARRAY_UNIQUE_SYMBOL cool_ARRAY_API
#include <numpy/arrayobject.h>

另一方面,coolhelper.c 将包含顶部内容

#define NO_IMPORT_ARRAY
#define PY_ARRAY_UNIQUE_SYMBOL cool_ARRAY_API
#include <numpy/arrayobject.h>

您也可以将最后两个通用行放入扩展本地头文件中,只要确保在 #包含该文件之前 #define 了 NO_IMPORT_ARRAY。

内部,这些 #defines 工作方式如下

  • 如果两者均未定义,则 C-API 被声明为 static void**,因此它仅在 #包含 numpy/arrayobject.h 的编译单元内可见。

  • 如果 #定义了 PY_ARRAY_UNIQUE_SYMBOL,但 _未_ 定义 NO_IMPORT_ARRAY,则 C-API 被声明为 void**,因此它也将对其他编译单元可见。

  • 如果 #定义了 NO_IMPORT_ARRAY,无论是否定义了 PY_ARRAY_UNIQUE_SYMBOL,C-API 都被声明为 extern void**,因此预计它将在另一个编译单元中定义。

  • 每当 #定义 PY_ARRAY_UNIQUE_SYMBOL 时,它还会更改保存 C-API 的变量的名称,该变量默认为 PyArray_API,更改为宏 #定义的任何内容。

检查 API 版本#

由于 Python 扩展在大多数平台上不像普通库那样使用,因此某些错误无法在构建时甚至运行时自动检测。例如,如果您使用仅适用于 numpy >= 1.3.0 的函数构建扩展,并在稍后使用 numpy 1.2 导入该扩展,您将不会收到导入错误(但几乎肯定会在调用函数时导致分段错误)。这就是为什么提供了几个函数来检查 numpy 版本。宏 NPY_VERSIONNPY_FEATURE_VERSION 对应于用于构建扩展的 numpy 版本,而函数 PyArray_GetNDArrayCVersionPyArray_GetNDArrayCFeatureVersion 返回的版本对应于运行时 numpy 的版本。

ABI 和 API 兼容性的规则可以总结如下

  • 每当 NPY_VERSION != PyArray_GetNDArrayCVersion() 时,都必须重新编译扩展(ABI 不兼容)。

  • NPY_VERSION == PyArray_GetNDArrayCVersion()NPY_FEATURE_VERSION <= PyArray_GetNDArrayCFeatureVersion() 表示向后兼容的更改。

ABI 不兼容在每个 numpy 版本中都会自动检测到。API 不兼容检测是在 numpy 1.4.0 中添加的。如果您想用一个扩展二进制文件支持许多不同的 numpy 版本,您必须使用最低的 NPY_FEATURE_VERSION 来构建您的扩展。

NPY_VERSION#

ndarray 对象的当前版本(检查此变量是否已定义以保证正在使用 numpy/arrayobject.h 头文件)。

NPY_FEATURE_VERSION#

C-API 的当前版本。

unsigned int PyArray_GetNDArrayCVersion(void)#

此函数仅返回 NPY_VERSION 的值。 NPY_VERSION 在 ABI 级别发生向后不兼容的更改时会发生变化。然而,由于它位于 C-API 中,因此将此函数的输出与当前头文件中定义的值进行比较,可以测试 C-API 是否已更改,从而需要重新编译使用 C-API 的扩展模块。这会在 import_array 函数中自动检查。

unsigned int PyArray_GetNDArrayCFeatureVersion(void)#

此函数仅返回 NPY_FEATURE_VERSION 的值。 NPY_FEATURE_VERSION 在 API 更改时(例如,添加函数)会发生变化。更改的值并不总是需要重新编译。

内存管理#

char *PyDataMem_NEW(size_t nbytes)#
void PyDataMem_FREE(char *ptr)#
char *PyDataMem_RENEW(void *ptr, size_t newbytes)#

用于分配、释放和重新分配内存的函数。除非被覆盖,否则它们内部用于管理数组数据内存。

npy_intp *PyDimMem_NEW(int nd)#
void PyDimMem_FREE(char *ptr)#
npy_intp *PyDimMem_RENEW(void *ptr, size_t newnd)#

用于分配、释放和重新分配维度和步幅内存的宏。

void *PyArray_malloc(size_t nbytes)#
void PyArray_free(void *ptr)#
void *PyArray_realloc(npy_intp *ptr, size_t nbytes)#

这些宏使用不同的内存分配器,具体取决于常量 NPY_USE_PYMEM。当 NPY_USE_PYMEM 为 0 时使用系统 malloc,如果 NPY_USE_PYMEM 为 1,则使用 Python 内存分配器。

NPY_USE_PYMEM#
int PyArray_ResolveWritebackIfCopy(PyArrayObject *obj)#

如果 obj->flags 具有 NPY_ARRAY_WRITEBACKIFCOPY,则此函数会清除标志,DECREF obj->base 并使其可写,并将 obj->base 设置为 NULL。然后它会将 obj->data 复制到 obj->base->data,并返回复制操作的错误状态。这与 PyArray_SetWritebackIfCopyBase 相反。通常,在完成 obj 后,在调用 Py_DECREF(obj) 之前,会调用一次此函数。它可以被多次调用,或使用 NULL 输入。另请参阅 PyArray_DiscardWritebackIfCopy

如果未执行任何操作,则返回 0,如果发生错误,则返回 -1,如果执行了操作,则返回 1。

线程支持#

仅当 NPY_ALLOW_THREADS 在编译扩展模块期间求值为 True 时,这些宏才有意义。否则,这些宏等同于空白。Python 为每个 Python 进程使用单个全局解释器锁 (GIL),因此一次只有一个线程可以执行(即使在多 CPU 机器上)。在调用可能需要计算时间的已编译函数(并且对其他线程没有副作用,例如更新的全局变量)时,应释放 GIL,以便其他 Python 线程可以在执行耗时计算时运行。这可以使用两组宏来实现。通常,如果在代码块中使用了一个宏,则所有宏都必须在同一代码块中使用。NPY_ALLOW_THREADS 为 True(定义为 1),除非构建选项 -Ddisable-threading 设置为 true - 在这种情况下,NPY_ALLOW_THREADS 为 False(0)。

NPY_ALLOW_THREADS#

第 1 组#

此组用于调用可能耗时但未使用任何 Python C-API 调用的代码。因此,在计算期间应释放 GIL。

NPY_BEGIN_ALLOW_THREADS#

等同于 Py_BEGIN_ALLOW_THREADS,但它使用 NPY_ALLOW_THREADS 来确定宏是替换为空白还是不替换。

NPY_END_ALLOW_THREADS#

等同于 Py_END_ALLOW_THREADS,但它使用 NPY_ALLOW_THREADS 来确定宏是替换为空白还是不替换。

NPY_BEGIN_THREADS_DEF#

放在变量声明区域。此宏设置存储 Python 状态所需的变量。

NPY_BEGIN_THREADS#

放在不需要 Python 解释器的代码(没有 Python C-API 调用)之前。此宏保存 Python 状态并释放 GIL。

NPY_END_THREADS#

放在不需要 Python 解释器的代码之后。此宏获取 GIL 并从保存的变量中恢复 Python 状态。

void NPY_BEGIN_THREADS_DESCR(PyArray_Descr *dtype)#

如果 dtype 不包含在执行循环期间可能需要 Python 解释器的任意 Python 对象,则仅用于释放 GIL。

void NPY_END_THREADS_DESCR(PyArray_Descr *dtype)#

在使用此宏的 BEGIN 形式释放 GIL 的情况下,用于重新获取 GIL。

void NPY_BEGIN_THREADS_THRESHOLDED(int loop_size)#

如果 loop_size 超过最小阈值(当前设置为 500),则仅用于释放 GIL。应与 NPY_END_THREADS 匹配以重新获取 GIL。

第 2 组#

此组用于在 GIL 已释放后重新获取 Python GIL。例如,假设 GIL 已释放(使用前面的调用),然后代码中的某个路径(可能在不同的子例程中)需要调用 Python C-API,那么这些宏对于获取 GIL 非常有用。这些宏本质上执行与前面三个宏相反的操作(获取 LOCK 并保存其状态),然后使用保存的状态重新释放它。

NPY_ALLOW_C_API_DEF#

放在变量声明区域以设置必要的变量。

NPY_ALLOW_C_API#

放在需要调用 Python C-API 的代码之前(当已知 GIL 已被释放时)。

NPY_DISABLE_C_API#

放在需要调用 Python C-API 的代码之后(以重新释放 GIL)。

提示

切勿在线程支持宏后使用分号。

优先级#

NPY_PRIORITY#

数组的默认优先级。

NPY_SUBTYPE_PRIORITY#

默认子类型优先级。

NPY_SCALAR_PRIORITY#

默认标量优先级(非常小)

double PyArray_GetPriority(PyObject *obj, double def)#

返回 obj__array_priority__ 属性(转换为 double),如果不存在同名属性,则返回 def。对于 PyArray_Type 类型的对象,提供可以避免属性查找的快速返回。

默认缓冲区#

NPY_BUFSIZE#

用户可设置的内部缓冲区的默认大小。

NPY_MIN_BUFSIZE#

用户可设置的内部缓冲区的最小大小。

NPY_MAX_BUFSIZE#

用户可设置的缓冲区的最大允许大小。

其他常量#

NPY_NUM_FLOATTYPE#

浮点类型的数量

NPY_MAXDIMS#

NumPy 可以使用的最大维度数。此值为 64,在 NumPy 2 之前为 32。

注意

我们建议您避免使用 NPY_MAXDIMS。未来的 NumPy 版本可能会希望移除任何维度限制(以及因此移除常量)。创建此限制是为了让 NumPy 可以在内部使用堆栈分配作为暂存空间。

如果您的算法具有合理的维度最大值,您可以在本地进行检查并使用它。

NPY_MAXARGS#

某些函数中可以使用的数组参数的最大数量。在 NumPy 2 之前,此值为 32,现在为 64。为了继续将其用作检查参数数量是否与 ufunc 兼容,此宏现在是运行时依赖的。

注意

我们不建议任何不明确用于检查已知 NumPy 限制的 NPY_MAXARGS 用途。

NPY_FALSE#

定义为 0,用于 Bool。

NPY_TRUE#

定义为 1,用于 Bool。

NPY_FAIL#

使用 PyArg_ParseTuple 类函数中的“O&”语法调用的转换器函数的失败返回值。

NPY_SUCCEED#

使用 PyArg_ParseTuple 类函数中的“O&”语法调用的转换器函数的成功返回值。

NPY_RAVEL_AXIS#

一些 NumPy 函数(主要是 Python 函数的 C 入口点)有一个 axis 参数。此宏可以传递给 axis=None

注意

此宏在运行时依赖于 NumPy 版本。其值现在是最小值。然而,在 NumPy 1.x 中,使用 NPY_MAXDIMS(当时设置为 32)。

其他宏#

int PyArray_SAMESHAPE(PyArrayObject *a1, PyArrayObject *a2)#

当数组 a1a2 具有相同的形状时,评估为 True。

PyArray_MAX(a, b)#

返回 ab 中的最大值。如果 (a) 或 (b) 是表达式,则它们会被评估两次。

PyArray_MIN(a, b)#

返回 ab 中的最小值。如果 (a) 或 (b) 是表达式,则它们会被评估两次。

void PyArray_DiscardWritebackIfCopy(PyArrayObject *obj)#

如果 obj->flags 具有 NPY_ARRAY_WRITEBACKIFCOPY,则此函数会清除标志,DECREF obj->base 并使其可写,并将 obj->base 设置为 NULL。与 PyArray_ResolveWritebackIfCopy 不同,它不会尝试将数据从 obj->base 复制。这会撤销 PyArray_SetWritebackIfCopyBase。通常,在出错后,当您完成 obj 时,在调用 Py_DECREF(obj) 之前,会调用此函数。它可以被多次调用,或使用 NULL 输入。

枚举类型#

enum NPY_SORTKIND#

一种特殊的变量类型,可以取不同的值来指示正在使用的排序算法。这些算法类型在一段时间内未严格对待,而是被视为稳定/不稳定。在 NumPy 2.4 中,它们被要求(见下文)所取代,但以向后兼容的方式完成。这些值将继续有效,只是 NPY_HEAPSORT 将与 NPY_QUICKSORT 执行相同操作。

enumerator NPY_QUICKSORT#
enumerator NPY_HEAPSORT#
enumerator NPY_MERGESORT#
enumerator NPY_STABLESORT#

用作 NPY_MERGESORT 的别名,反之亦然。

enumerator NPY_NSORTS#

定义为排序的数量。由于向后兼容性的需要,它被固定为三个,因此 NPY_MERGESORTNPY_STABLESORT 是相互别名的,并且可能取决于数据类型,指向几种稳定排序算法之一。

在 NumPy 2.4 中,算法名称被要求所取代。您仍然可以使用旧值,无需重新编译,但它们会被重新解释,以便:

  • NPY_QUICKSORT 和 NPY_HEAPSORT -> NPY_SORT_DEFAULT

  • NPY_MERGESORT 和 NPY_STABLE -> NPY_SORT_STABLE

enumerator NPY_SORT_DEFAULT#

类型的默认排序。对于 NumPy 内置类型,它可能是稳定的,也可能不是,但将是升序的,并将 NaN 类型排序到最后。它通常因速度快和/或内存占用少而选择。

enumerator NPY_SORT_STABLE#

(要求)指定排序必须是稳定的。

enumerator NPY_SORT_DESCENDING#

(要求)指定排序必须是降序的。此功能尚未为任何 NumPy 类型实现,并且目前无法从 Python 接口进行设置。

enum NPY_SCALARKIND#

一种特殊的变量类型,指示在确定标量强制转换规则时区分的标量“种类”的数量。此变量可以取以下值:

enumerator NPY_NOSCALAR#
enumerator NPY_BOOL_SCALAR#
enumerator NPY_INTPOS_SCALAR#
enumerator NPY_INTNEG_SCALAR#
enumerator NPY_FLOAT_SCALAR#
enumerator NPY_COMPLEX_SCALAR#
enumerator NPY_OBJECT_SCALAR#
enumerator NPY_NSCALARKINDS#

定义为标量类型的数量(不包括 NPY_NOSCALAR)。

enum NPY_ORDER#

一个枚举类型,指示数组应解释的元素顺序。当创建一个全新的数组时,通常只使用 NPY_CORDERNPY_FORTRANORDER,而当提供一个或多个输入时,顺序可以基于这些输入。

enumerator NPY_ANYORDER#

如果所有输入都是 Fortran 顺序,则为 Fortran 顺序,否则为 C 顺序。

enumerator NPY_CORDER#

C 顺序。

enumerator NPY_FORTRANORDER#

Fortran 顺序。

enumerator NPY_KEEPORDER#

尽可能接近输入顺序的顺序,即使输入既不是 C 顺序也不是 Fortran 顺序。

enum NPY_CLIPMODE#

一个变量类型,指示在某些函数中应应用哪种类型的裁剪。

enumerator NPY_RAISE#

大多数操作的默认值,如果在边界外引发异常。

enumerator NPY_CLIP#

如果索引超出边界,则将索引裁剪到有效范围。

enumerator NPY_WRAP#

如果索引超出边界,则将索引包装到有效范围。

enum NPY_SEARCHSIDE#

一个变量类型,指示返回的索引应是第一个合适位置的索引(如果 NPY_SEARCHLEFT)还是最后一个合适位置的索引(如果 NPY_SEARCHRIGHT)。

enumerator NPY_SEARCHLEFT#
enumerator NPY_SEARCHRIGHT#
enum NPY_SELECTKIND#

一个变量类型,指示正在使用的选择算法。

enumerator NPY_INTROSELECT#
enum NPY_CASTING#

一个枚举类型,指示数据转换的容忍度。这由 NumPy 1.6 中添加的迭代器使用,并计划在未来版本中更广泛地使用。

enumerator NPY_NO_CASTING#

只允许类型相同。

enumerator NPY_EQUIV_CASTING#

允许类型相同和涉及字节交换的转换。

enumerator NPY_SAFE_CASTING#

只允许不会导致值舍入、截断或以其他方式更改的转换。

enumerator NPY_SAME_KIND_CASTING#

允许任何安全的转换,以及相同类型之间的转换。例如,此规则允许 float64 -> float32。

enumerator NPY_UNSAFE_CASTING#

允许任何转换,无论可能发生何种数据丢失。

NPY_SAME_VALUE_CASTING#

如果在转换过程中任何值发生更改,则报错。目前仅在 ndarray.astype(... casting='same_value') 中支持。

版本 2.4 中的新功能。