Array API#

一流的智力是指能够同时在头脑中容纳两种对立的思想,
并仍能保持正常运作的能力。
F. Scott Fitzgerald
对于一项成功的技术,现实必须优先于公共关系,
因为自然界是骗不了的。
Richard P. Feynman
数组结构和数据访问#

这些宏访问 PyArrayObject 结构成员,并在 ndarraytypes.h 中定义。输入参数 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 并将其放置在由 itemptr 指向的 ndarray arr 中。如果发生错误则返回 -1,成功则返回 0。

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

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

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 \(^{\textrm{th}}\) 维的形状。

npy_intp PyArray_STRIDE(PyArrayObject *arr, int n)#

返回第 n \(^{\textrm{th}}\) 维的步长。

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 arr 中,在由 itemptr 指向的位置,获取一个内置类型的 Python 对象。失败时返回 NULL

numpy.ndarray.item 与 PyArray_GETITEM 相同。

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

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

数据访问#

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

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

返回指向 ndarray aobj 数据(在 C 数组 ind 给定的 N 维索引处)的指针(ind 的大小必须至少为 aobj ->nd)。您可能需要将返回的指针类型转换为 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 中给定坐标处的元素,obj 必须分别具有 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 的对象,subtype 必须是 PyArray_Type 的子类型。该数组有 nd 个维度,由 dims 描述。新数组的数据类型描述符是 descr

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

如果 dataNULL,则会分配新的未初始化内存,并且 flags 可以是非零值,表示 Fortran 风格的连续数组。使用 PyArray_FILLWBYTE 初始化内存。

如果 data 不是 NULL,则假定它指向用于数组的内存,并且 flags 参数用作数组的新标志(除了 NPY_ARRAY_OWNDATANPY_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 指定此数组的特定大小。

警告

如果将数据传递给 PyArray_NewFromDescrPyArray_New,则在删除新数组之前,此内存不得被释放。如果此数据来自另一个引用计数的 Python 对象,则可以通过对该对象使用 Py_INCREF 并将新数组的基成员设置为指向拥有该数据的 Python 对象来完成。这将确保在返回的数组存在期间不会释放提供的内存。如果传递了步长,它们必须与数组的维度、项目大小和数据一致。

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 指示。如果数据来自另一个引用计数的 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 指向的数组——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 的新 1 维数组,范围从 startstop(不包含),增量为 step。等同于 arange (start, stop, step, dtype)。

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

构造一个数据类型由 descr 确定的新 1 维数组,范围从 startstop(不包含),增量为 step。等同于 arange( start, stop, step, typenum )。

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

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

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

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

如果提供的对象是一个数组,此函数将遍历 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,表示任何数据类型(和字节顺序)都是可接受的。除非 flags 中存在 NPY_ARRAY_FORCECAST,否则如果无法安全地从对象获取数据类型,此调用将生成错误。如果您想将 dtype 使用 NULL 并确保数组未交换,则使用 PyArray_CheckFromAny。深度参数中的任何一个为 0 都表示该参数被忽略。以下任何数组标志都可以添加(例如使用 |)以获取 requirements 参数。如果您的代码可以处理通用数组(例如,带步长、字节交换或未对齐的数组),则 requirements 可以为 0。此外,如果 op 尚未是数组(或未公开数组接口),则将创建一个新数组(并使用序列协议从 op 填充)。新数组的 flags 成员将为 NPY_ARRAY_DEFAULTcontext 参数未使用。

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)#

op 已经是数组但需要特定 newtype(包括字节顺序)或具有某些 requirements 时,PyArray_FromAny 的特殊情况。

PyObject *PyArray_FromStructInterface(PyObject *op)#

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)#

此函数从任何嵌套序列或导出数组接口的对象 *op* 中返回一个(C 风格的)连续且行为良好的函数数组,其类型由枚举的 *typenum* 给出(非灵活类型),最小深度为 *min_depth*,最大深度为 *max_depth*。等同于调用 PyArray_FromAny,其中要求设置为 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,并要求 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,并将要求设置为 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 为负,则其值将根据缓冲区大小和请求的 itemsize 确定;否则,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_OFPyArray_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_ENSURECOPY 作为要求传入,此宏还会将 NPY_ARRAY_DEFAULT 添加到要求中。

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* 是一个 Python 对象,其类型是 PyArray_Type 的子类型,则评估为真。

int PyArray_CheckExact(PyObject *op)#

如果 *op* 是一个类型为 PyArray_Type 的 Python 对象,则评估为真。

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 的子类型实例)或者 PyArray_Type 的实例(或其子类)且维数为 0,则评估为真。

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 的子类型实例)或 PyArray_Type 的子类型实例且维数为 0,则评估为真。

数据类型访问器#

某些描述符属性可能并非总是定义,不应或无法直接访问。

版本 2.0 中的变更:在 NumPy 2.0 之前,ABI 不同,但对于用户 DType 来说过于庞大。这些访问器均在 2.0 版本中添加,并且可以向后移植(参见 PyArray_Descr 结构已更改)。

npy_intp PyDataType_ELSIZE(PyArray_Descr *descr)#

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

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

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

void PyDataType_SET_ELSIZE(PyArray_Descr *descr, npy_intp size)#

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

npy_intp PyDataType_ALIGNENT(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)#

NULL, None,或结构化 dtype 字段的字典,此字典不得被修改,NumPy 未来可能会改变字段的存储方式。

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

NpyAuxData *PyDataType_C_METADATA(PyArray_Descr *descr)#

附加到描述符的 C 元数据对象。通常不需要此访问器。C 元数据字段确实提供了对 datetime/timedelta 时间单位信息的访问。

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 宏,参数是一个表示枚举数组数据类型的整数。对于数组类型检查宏,参数必须是可直接解释为 PyArrayObject*PyObject*

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_STRING, NPY_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)#

如果 *type1* 和 *type2* 在此平台上实际表示等效类型(每个类型的 fortran 成员被忽略),则返回 `NPY_TRUE`。例如,在 32 位平台上,`NPY_LONG``NPY_INT` 是等效的。否则返回 `NPY_FALSE`

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

如果 *a1* 和 *a2* 是在此平台上具有等效类型的数组,则返回 `NPY_TRUE`

int PyArray_EquivTypenums(int typenum1, int typenum2)#

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

int PyArray_EquivByteorders(int b1, int b2)#

如果字节序字符 *b1* 和 *b2* (`NPY_LITTLE``NPY_BIG``NPY_NATIVE``NPY_IGNORE`)在指定本机字节序方面相等或等效,则为 True。因此,在小端机器上,`NPY_LITTLE``NPY_NATIVE` 是等效的,而在大端机器上则不等效。

转换数据类型#

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

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

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 等灵活类型,它会考虑其大小生成结果。整数和浮点类型只有在使用 `NPY_SAFE_CASTING` 转换为字符串或 unicode 类型时,目标字符串或 unicode 类型足够大以容纳源整数/浮点类型的最大值才可安全转换。

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

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

PyArray_Descr *PyArray_MinScalarType(PyArrayObject *arr)#

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

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

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

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

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

找到 *type1* 和 *type2* 可以安全转换到的最小大小和类型的数据类型。此函数是对称且关联的。字符串或 unicode 结果将是存储转换为字符串或 unicode 的输入类型的最大值的适当大小。

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

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

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

int PyArray_ObjectType(PyObject *op, int mintype)#

此函数已被 `PyArray_ResultType` 取代。

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

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

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

将 *op* 中包含的 Python 对象序列转换为 ndarray 数组,每个 ndarray 具有相同的数据类型。类型的选择方式与 `PyArray_ResultType` 相同。序列的长度在 *n* 中返回,并且返回一个 *n* 长度的 `PyArrayObject` 指针数组(如果发生错误则为 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)#

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

自 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,你需要添加自己的锁,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*,使其可以从给定 *scalar* 类型的 *descr* 数据类型对象进行转换。使用 *scalar* = `NPY_NOSCALAR` 来注册数据类型为 *descr* 的数组可以安全地转换为类型编号为 *totype* 的数据类型。成功时返回 0,失败时返回 -1。

NPY_OBJECT 的特殊函数#

如果将数据传递给 PyArray_NewFromDescrPyArray_New,则在删除新数组之前,此内存不得被释放。如果此数据来自另一个引用计数的 Python 对象,则可以通过对该对象使用 Py_INCREF 并将新数组的基成员设置为指向拥有该数据的 Python 对象来完成。这将确保在返回的数组存在期间不会释放提供的内存。如果传递了步长,它们必须与数组的维度、项目大小和数据一致。

在使用填充了对象的数组或缓冲区时,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_CONTIGUOUS``NPY_ARRAY_BEHAVED`),则将这些要求传递给 PyArray_FromAny 函数。

在 NumPy 1.6 及更早版本中,以下标志不包含 _ARRAY_ 宏命名空间。这种常量名称形式在 1.7 版本中已弃用。

基本数组标志#

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

NPY_ARRAY_C_CONTIGUOUS#

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

NPY_ARRAY_F_CONTIGUOUS#

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

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

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

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

NPY_ARRAY_OWNDATA#

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

NPY_ARRAY_ALIGNED#

数据区域和所有数组元素都已适当对齐。

NPY_ARRAY_WRITEABLE#

数据区域可写。

请注意,上述 3 个标志的定义使得一个行为良好的新数组会将其定义为真。

NPY_ARRAY_WRITEBACKIFCOPY#

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

这是一个特殊标志,如果此数组表示因用户在 `PyArray_FromAny` 中要求某些标志而创建的副本,并且必须创建另一个数组的副本(并且用户在这种情况下要求设置此标志),则会设置此标志。然后,base 属性指向“行为不佳”的数组(该数组被设置为只读)。`PyArray_ResolveWritebackIfCopy` 将其内容复制回“行为不佳”的数组(如果需要则进行类型转换),并将“行为不佳”的数组重置为 `NPY_ARRAY_WRITEABLE`。如果“行为不佳”的数组最初不是 `NPY_ARRAY_WRITEABLE`,那么 `PyArray_FromAny` 将返回错误,因为 `NPY_ARRAY_WRITEBACKIFCOPY` 将不可能实现。

`PyArray_UpdateFlags` (obj, flags) 将更新 obj->flags 中由 flags 指定的标志,flags 可以是 `NPY_ARRAY_C_CONTIGUOUS``NPY_ARRAY_F_CONTIGUOUS``NPY_ARRAY_ALIGNED``NPY_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_CONTIGUOUS``NPY_ARRAY_F_CONTIGUOUS``NPY_ARRAY_OWNDATA``NPY_ARRAY_ALIGNED``NPY_ARRAY_WRITEABLE``NPY_ARRAY_WRITEBACKIFCOPY`

int PyArray_IS_C_CONTIGUOUS(const PyArrayObject *arr)#

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

int PyArray_IS_F_CONTIGUOUS(const PyArrayObject *arr)#

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

int PyArray_ISFORTRAN(const PyArrayObject *arr)#

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

int PyArray_ISWRITEABLE(const PyArrayObject *arr)#

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

int PyArray_ISALIGNED(const PyArrayObject *arr)#

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

int PyArray_ISBEHAVED(const PyArrayObject *arr)#

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

int PyArray_ISBEHAVED_RO(const PyArrayObject *arr)#

如果 *arr* 的数据区域已对齐且采用机器字节序,则评估为真。

int PyArray_ISCARRAY(const PyArrayObject *arr)#

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

int PyArray_ISFARRAY(const PyArrayObject *arr)#

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

int PyArray_ISCARRAY_RO(const PyArrayObject *arr)#

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

int PyArray_ISFARRAY_RO(const PyArrayObject *arr)#

如果 *arr* 的数据区域是 Fortran 风格连续、已对齐且采用机器字节序**。**

int PyArray_ISONESEGMENT(const PyArrayObject *arr)#

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

void PyArray_UpdateFlags(PyArrayObject *arr, int flagmask)#

数组标志 `NPY_ARRAY_C_CONTIGUOUS``NPY_ARRAY_ALIGNED``NPY_ARRAY_F_CONTIGUOUS` 可以从数组对象本身“计算”得出。此例程通过执行所需计算来更新 *arr* 中由 *flagmask* 指定的一个或多个这些标志。

如果将数据传递给 PyArray_NewFromDescrPyArray_New,则在删除新数组之前,此内存不得被释放。如果此数据来自另一个引用计数的 Python 对象,则可以通过对该对象使用 Py_INCREF 并将新数组的基成员设置为指向拥有该数据的 Python 对象来完成。这将确保在返回的数组存在期间不会释放提供的内存。如果传递了步长,它们必须与数组的维度、项目大小和数据一致。

在对数组进行可能导致标志更改的操作时,保持标志更新非常重要(使用 `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 和 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,则输出描述符也将被传入,并且不应被覆盖。

方法 是指向底层类型转换或ufunc循环的指针。将来我们可能会公开这个结构,但目前它是一个不透明指针,无法检查该方法。 dtypes 是一个长度为 nargsPyArray_DTypeMeta 指针数组, given_descrs 是一个长度为 nargs 的输入描述符实例数组(如果用户未提供输出,则输出描述符可能为 NULL),而 loop_descrs 是一个长度为 nargs 的描述符数组,必须由解析描述符的实现填充。 view_offset 目前仅对类型转换(cast)感兴趣,通常可以忽略。当类型转换不需要任何操作时,可以通过将 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还是类型转换)的一维跨步循环。在大多数情况下,NPY_METH_strided_loop 是唯一需要实现的通用版本。NPY_METH_contiguous_loop 可以作为更轻量/更快的版本额外实现,并在所有输入和输出都连续时使用。

为了处理可能未对齐的数据,NumPy 需要能够将未对齐的数据复制到已对齐的数据。当实现一个新的 DType 时,它的“类型转换”或复制需要实现 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;

未对齐循环目前仅用于类型转换,永远不会在ufunc中选择(ufunc会创建临时副本以确保输入对齐)。当定义了 NPY_METH_get_loop 时,这些槽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 循环的实现。上面列出的所有循环槽ID都必须提供 PyArrayMethod_StridedLoop 实现。 context 是一个包含循环操作上下文的结构体——特别是输入描述符。 data 是指向输入和输出数组缓冲区开头的指针数组。 dimensions 是操作的循环维度。 strides 是一个长度为 nargs 的每个输入的步长数组。 auxdata 是一组可选的辅助数据,可以传递给循环——这有助于开启和关闭可选行为,或者通过允许相似的ufunc共享循环实现来减少样板代码,或者分配在多次跨步循环调用中持久存在的空间。

NPY_METH_get_loop#

允许对循环选择进行更细粒度的控制。接受 PyArrayMethod_GetLoop 的实现,该实现反过来返回一个跨步循环实现。如果定义了 NPY_METH_get_loop,则其他循环槽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]) 的符号。

  • 我们不对对象使用标识值,但对于空的 sum([], dtype=object)prod([], dtype=object) 返回默认值 01。这使得 np.sum(np.array(["a", "b"], dtype=object)) 可以工作。

  • -infINT_MIN 对于 max 是一个标识值,但至少 INT_MIN 在没有项目时不是一个好的 默认值

initial 是指向初始值数据的一个指针,应该填充。返回 -1、0 或 1,分别表示错误、没有初始值和初始值已成功填充。当没有初始值是正确情况时,不能给出错误,因为 NumPy 即使在没有严格必要时也可能调用此函数。

标志#

enum NPY_ARRAYMETHOD_FLAGS#

这些标志允许为 ArrayMethod 循环开启和关闭自定义运行时行为。例如,如果 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#

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

类型定义#

下面描述了 ArrayMethod API 用户可以实现的函数的类型定义。

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

作用于单个数组的遍历循环。这类似于通用的跨步循环函数。它专为需要访问单个数组每个元素的循环而设计。

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

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

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

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)#

简化版的 get_loop 函数,专门用于 dtype 遍历

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

API 函数和类型定义#

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

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

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

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

请注意,除非输出 dtypes 也是签名的一部分,否则目前它们始终为 NULL。这是一个实现细节,将来可能会改变。然而,一般来说,推广器不需要输出 dtypes。为 ufunc 注册一个新的推广器。第一个参数是要注册推广器的 ufunc。第二个参数是一个 Python 元组,包含 DType 或 None,与 ufunc 的输入和输出数量匹配。最后一个参数推广器是一个存储在 PyCapsule 中的函数。它被传递操作和请求的 DType 签名,并且可以修改它以尝试新的匹配循环/推广器搜索。

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

推广器函数的类型,必须封装在名为 "numpy._ufunc_promoter"PyCapsule 中。它被传递操作和请求的 DType 签名,并且可以修改签名以尝试搜索新的循环或推广器,该循环或推广器可以通过将输入转换为“推广的”DType 来完成操作。

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)并为包装的循环进行转换。新的描述符必须与旧的描述符兼容(viewable),必须支持 NULL(对于输出参数),并且通常应转发。

此函数的输出将用于构造参数的视图,就好像它们是转换后的 dtypes 一样,并且不使用类型转换。这意味着此机制主要用于“包装”另一个 DType 实现的 DType。例如,一个单位 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 函数返回)转换为输出数组应使用的描述符。此函数必须返回“可视图(viewable)”类型,它不得以任何会破坏内循环逻辑的形式修改它们。不需要支持 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]);
}

调用数组方法的 API#

转换#

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

等同于 ndarray.getfield (self, dtype, offset)。此函数 窃取对 PyArray_Descr 的引用,并返回一个使用当前数组中指定字节 offset 处数据的新数组,其 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 的字段设置为 valoffset 加上 dtype ->elsize 必须小于 self ->descr->elsize,否则会引发错误。否则, val 参数将被转换为数组并复制到指向的字段中。如有必要, val 的元素将被重复以填充目标数组,但目标中的元素数量必须是 val 中元素数量的整数倍。

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

等同于 ndarray.byteswap (self, inplace)。返回一个数据区已字节交换的数组。如果 inplace 非零,则原地执行字节交换并返回对自身的引用。否则,创建一个字节交换的副本,并保持自身不变。

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

等同于 ndarray.copy (self, fortran)。复制 old 数组。返回的数组始终是对齐且可写的,数据解释与旧数组相同。如果 orderNPY_CORDER,则返回 C 风格的连续数组。如果 orderNPY_FORTRANORDER,则返回 Fortran 风格的连续数组。如果 orderNPY_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 print 语句格式字符串,显示如何写入项目。

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

如果 dtypeNULL,则返回的数组将与 self 具有相同的数据类型。新的数据类型必须与 self 的大小一致。要么 itemsize 必须相同,要么 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_NewFromDescrPyArray_New,则在删除新数组之前,此内存不得被释放。如果此数据来自另一个引用计数的 Python 对象,则可以通过对该对象使用 Py_INCREF 并将新数组的基成员设置为指向拥有该数据的 Python 对象来完成。这将确保在返回的数组存在期间不会释放提供的内存。如果传递了步长,它们必须与数组的维度、项目大小和数据一致。

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

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

等同于 ndarray.swapaxes (self, a1, a2)。返回的数组是 self 中数据的新视图,其中给定的轴 a1a2 已交换。

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

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

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

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

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

等同于 ndarray.flatten (self, order)。返回数组的 1 维副本。如果 orderNPY_FORTRANORDER,则元素以 Fortran 顺序(第一维变化最快)扫描。如果 orderNPY_CORDER,则 self 的元素以 C 顺序(最后一维变化最快)扫描。如果 orderNPY_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 来实现。沿给定 axisself 中提取由整数值 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)#

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

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

等同于 ndarray.repeat (self, op, axis)。沿给定 axisself 的元素重复 op 次。`op` 可以是标量整数,也可以是长度为 `self->dimensions[axis]` 的序列,指示沿 `axis` 重复每个项目多少次。

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

等同于 ndarray.choose (self, op, ret, clipmode)。根据 self 中的整数值,从 op 中的数组序列中选择元素,创建一个新数组。所有数组都必须可广播到相同的形状,并且 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)#

等同于 ndarray.sort (self, axis, kind)。返回一个沿 axisself 的项目进行排序的数组。该数组使用 kind 指定的算法进行排序,kind 是一个整数/枚举,指示所使用的排序算法类型。

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

等同于 ndarray.argsort (self, axis)。返回一个索引数组,沿给定 axis 选择这些索引将返回 self 的排序版本。如果 `self->descr` 是一个定义了字段的数据类型,那么 `self->descr->names` 将用于确定排序顺序。如果第一个字段相等,则比较第二个字段,以此类推。要更改结构化数组的排序顺序,请创建一个具有不同名称顺序的新数据类型,并使用该新数据类型构造数组的视图。

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

给定一组形状相同的数组(sort_keys),返回一个索引数组(类似于 PyArray_ArgSort (…)),这些索引将按字典顺序对数组进行排序。字典序排序规定,当两个键相等时,顺序基于后续键的比较。对于这些类型,需要定义归并排序(它保持相等条目不动)。排序通过首先使用第一个 sort_key 排序索引,然后使用第二个 sort_key 等等来完成。这等同于 Python 命令 `lexsort(sort_keys, axis)`。由于归并排序的工作方式,请务必理解 sort_keys 必须遵循的顺序(与您比较两个元素时使用的顺序相反)。

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

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

等同于 ndarray.searchsorted (self, values, side, perm)。假设 self 是一个升序的一维数组,则输出是一个与 values 形状相同的索引数组,这样如果 values 中的元素插入到这些索引之前,self 的顺序将保持不变。不检查 self 是否为升序。

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

`sorter` 参数如果不是 NULL,则必须是一个与 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 定义的二维数组的 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 相同的效果(将数组视为一维数组)。

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

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

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

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

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

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

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

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

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

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

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

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

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

`rtype` 参数指定了归约操作应采用的数据类型。如果数组的数据类型不足以处理输出,这一点很重要。默认情况下,对于“add”和“multiply”ufuncs(它们是 mean、sum、cumsum、prod 和 cumprod 函数的基础),所有整数数据类型都至少会转换为 NPY_LONG 大小。

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)#

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

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

等同于 ndarray.clip (self, min, max)。裁剪数组 self,使得大于 max 的值固定为 max,小于 min 的值固定为 min

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

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

参数:
  • self – 输入数组。

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

返回:

self 的复共轭。

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

等同于 ndarray.round (self, decimals, out)。返回元素四舍五入到最接近的小数位的数组。小数位定义为 \(10^{-\textrm{decimals}}\) 位,因此负 decimals 会导致四舍五入到最接近的 10、100 等。如果 `out` 为 NULL,则创建输出数组;否则,输出将放置在 out 中,out 必须具有正确的大小和类型。

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

等同于 ndarray.std (self, axis, rtype)。返回沿 axis 的数据转换成数据类型 rtype 后的标准差。

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

等同于 ndarray.sum (self, axis, rtype)。返回 self 沿 axis 的元素的一维向量和。在将数据转换成数据类型 rtype 后执行求和。

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

等同于 ndarray.cumsum (self, axis, rtype)。返回 self 沿 axis 的元素的累积一维和。在将数据转换成数据类型 rtype 后执行求和。

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

等同于 ndarray.prod (self, axis, rtype)。返回 self 沿 axis 的元素的一维乘积。在将数据转换成数据类型 rtype 后执行乘积。

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

等同于 ndarray.cumprod (self, axis, rtype)。返回 self 沿 axis 的元素的累积一维乘积。在将数据转换成数据类型 rtype 后执行乘积。

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

等同于 ndarray.all (self, axis)。对于 axis 定义的 self 的每个一维子数组,如果所有元素都为 True,则返回一个包含 True 元素的数组。

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

等同于 ndarray.any (self, axis)。对于 axis 定义的 self 的每个一维子数组,如果任何元素为 True,则返回一个包含 True 元素的数组。

函数#

数组函数#

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

有时,将多维数组作为 C 风格的多维数组访问会很有用,这样就可以使用 C 语言的 `a[i][j][k]` 语法实现算法。此例程返回一个指针 ptr,它模拟这种 C 风格数组,适用于一维、二维和三维 ndarray。

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

  • ptr – 一个(一维为 `ctype*`,二维为 `ctype**` 或三维为 `ctype***`)变量的地址,其中 `ctype` 是数据类型的等效 C 类型。返回时,ptr 将可以作为一维、二维或三维数组寻址。

  • dims – 包含数组对象形状的输出数组。此数组为将要发生的任何循环提供边界。

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

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

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

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

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

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

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

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

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

计算 obj1obj2 的最后维度上的乘积和。两个数组都没有被共轭。

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

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

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)#

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

备注

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

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

`PyArray_Correlate` 的更新版本,它使用一维数组的通常相关性定义。通过将 op1 乘以 op2 的移位版本并求和结果,在每个输出点计算相关性。由于移位,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 指示的位置,该数组的大小必须至少为 iterator ->nd_m1+1。

void PyArray_ITER_GOTO1D(PyObject *iterator, npy_intp index)#

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

int PyArray_ITER_NOTDONE(PyObject *iterator)#

只要迭代器尚未遍历所有元素,则评估为 TRUE,否则评估为 FALSE。

广播 (多迭代器)#

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

广播的简化接口。此函数接受要广播的数组数量,然后是 num 个额外( PyObject * )参数。这些参数被转换为数组并创建迭代器。然后对生成的多迭代器对象调用 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 \(^{\textrm{th}}\) 迭代器的数据指针。

void PyArray_MultiIter_NEXTi(PyObject *multi, int i)#

只推进第 i \(^{\textrm{th}}\) 迭代器的指针。

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 新增。

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

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,否则返回相应的维度,如果为 0 则返回 -1。此函数可用于构建类似 ufunc 的例程,这些例程正确广播其输入,然后将步进 1 维版本的例程作为内部循环调用。此 1 维版本通常针对速度进行了优化,因此循环应在不需要大步长跳转的轴上执行。

邻域迭代器#

邻域迭代器是迭代器对象的子类,可用于遍历某个点的邻域。例如,您可能希望遍历 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)#

通过从 data 指向的内存中**复制**,返回给定 dtype 的数组标量对象。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(应为数组标量对象)返回一个 0 维数组,其类型由 outcode 确定。如果 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 指向的内存中(该内存必须足够大以处理传入的数据)。

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

PyObject *PyArray_TypeObjectFromType(int type)#

从类型编号 type 返回一个标量类型对象。等效于 PyArray_DescrFromType (type)->typeobj,但引用计数和错误检查除外。成功时返回对类型对象的新引用,失败时返回 NULL

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

查询标量值特殊提升的传统方法。这在 NumPy 本身中已不再使用,并预计最终将被弃用。

新的 DType 可以定义特定于 Python 标量的提升规则。

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

查询标量值特殊提升的传统方法。这在 NumPy 本身中已不再使用,并预计最终将被弃用。

使用 PyArray_ResultType 实现类似目的。

数据类型描述符#

如果将数据传递给 PyArray_NewFromDescrPyArray_New,则在删除新数组之前,此内存不得被释放。如果此数据来自另一个引用计数的 Python 对象,则可以通过对该对象使用 Py_INCREF 并将新数组的基成员设置为指向拥有该数据的 Python 对象来完成。这将确保在返回的数组存在期间不会释放提供的内存。如果传递了步长,它们必须与数组的维度、项目大小和数据一致。

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

int PyArray_DescrCheck(PyObject *obj)#

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

PyArray_Descr *PyArray_DescrNew(PyArray_Descr *obj)#

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

PyArray_Descr *PyArray_DescrNewFromType(int typenum)#

typenum 指示的内置(或用户注册的)数据类型创建一个新的数据类型对象。所有内置类型都不应更改其任何字段。这将创建 PyArray_Descr 结构的新副本,以便您可以适当地填充它。此函数对于柔性数据类型尤其需要,因为它们需要一个新的 elsize 成员才能在数组构造中有意义。

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

创建一个新的数据类型对象,其字节序根据 newendian 设置。所有引用的数据类型对象(在数据类型对象的 subdescr 和 fields 成员中)也会被更改(递归地)。

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 参数设置为所需大小。typenum 是 NPY_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)#

以一种即使改变顺序也能保证稳定结果的方式,相互提升 DType 列表。此函数更智能,通常可以在 common_dtype(common_dtype(dt1, dt2), dt3) 依赖操作顺序或失败时返回成功且明确的结果。尽管如此,DType 仍应致力于确保其通用 dtype 实现是结合律和交换律的!(主要是无符号和有符号整数不是。)

为了保证一致的结果,DType 必须“传递性地”实现通用 DType。如果 A 提升 B 且 B 提升 C,则 A 通常也必须提升 C;其中“提升”意味着实现该提升。(抽象 DType 存在一些例外)

通常,只要最通用的 dtype 严格更大或与所有其他 dtype 兼容,此方法总是有效。例如,将 float16 与任何其他浮点数、整数或无符号整数进行提升,结果仍是浮点数。

PyArray_DTypeMeta *PyArray_GetDefaultDescr(const PyArray_DTypeMeta *DType)#

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

自定义数据类型#

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

这些函数允许在 NumPy 之外定义自定义的柔性数据类型。有关新 DType 系统的原理和设计的更多详细信息,请参阅NEP 42。有关 DType 示例,请参阅 numpy-user-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 的子类,并将其类型设置为 PyArrayDTypeMeta_Type(在调用 PyType_Ready 之前),后者与普通的 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)#

如果定义,此函数在创建数组后调用以“完成”描述符实例。此函数的一个用途是强制新创建的数组具有新创建的描述符实例,无论用户提供了什么输入描述符。

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 类型的**地址**。

如果将数据传递给 PyArray_NewFromDescrPyArray_New,则在删除新数组之前,此内存不得被释放。如果此数据来自另一个引用计数的 Python 对象,则可以通过对该对象使用 Py_INCREF 并将新数组的基成员设置为指向拥有该数据的 Python 对象来完成。这将确保在返回的数组存在期间不会释放提供的内存。如果传递了步长,它们必须与数组的维度、项目大小和数据一致。

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

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

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

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 转换为 npy_intp 的 C 数组。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 已经是指向另一个对象的缓冲区对象,则设置为其基)。如果您需要保留内存,请务必 INCREF base 成员。该内存块由 buf ->ptr 成员指向,长度为 buf ->len。如果 obj 具有可写缓冲区接口,则 buf 的 flags 成员被设置为 NPY_ARRAY_ALIGNED 并带有 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.harrayobject.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 的警告。

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

如果您遇到访问冲突,请确保 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 相同的行为。

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

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>

您也可以将最后两行公共代码放入扩展模块本地的头文件中,只要确保在 #include 该文件之前已 #defined NO_IMPORT_ARRAY。

在内部,这些 #define 的工作方式如下:

  • 如果两者均未定义,C-API 将被声明为 static void**,因此它仅在 #includes 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() 意味着向后兼容的更改。

每个 numpy 版本都会自动检测 ABI 不兼容性。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)#

当 GIL 是使用此宏的 BEGIN 形式释放时,可用于重新获取 GIL。

void NPY_BEGIN_THREADS_THRESHOLDED(int loop_size)#

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

组 2#

此组用于在 Python GIL 已释放后重新获取它。例如,假设 GIL 已被释放(使用之前的调用),然后代码中的某个路径(可能在不同的子程序中)需要使用 Python C-API,那么这些宏有助于获取 GIL。这些宏本质上完成了前三个宏的反向操作(获取锁并保存其状态),然后用保存的状态重新释放它。

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。

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

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

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

NPY_MAXARGS#

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

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

我们不鼓励使用任何非明确与检查已知 NumPy 限制相关的 NPY_MAXARGS

NPY_FALSE#

定义为 0,用于布尔值。

NPY_TRUE#

定义为 1,用于布尔值。

NPY_FAIL#

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

NPY_SUCCEED#

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

NPY_RAVEL_AXIS#

某些 NumPy 函数(主要是 Python 函数的 C 入口点)具有 `axis` 参数。此宏可用于 `axis=None`。

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

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

杂项宏#

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

如果数组 *a1* 和 *a2* 具有相同的形状,则评估为 True。

PyArray_MAX(a, b)#

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

PyArray_MIN(a, b)#

返回 *a* 和 *b* 的最小值。如果 (*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#

一种特殊变量类型,可以取不同的值来指示正在使用的排序算法。

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

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

enumerator NPY_NSORTS#

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

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#

允许任何转换,无论可能发生何种数据丢失。