C代码中定义了几种新类型。其中大多数都可以从Python访问,但有一些由于使用有限而没有公开。每个新的python类型都有一个 PyObject* 内部结构包含指向“方法表”的指针,该“方法表”定义新对象在Python中的行为。当您在C代码中接收到一个python对象时,您总是得到一个指向 PyObject 结构。因为A PyObject 结构非常通用,只定义 PyObject_HEAD 它本身就不是很有趣。但是,不同的对象在 PyObject_HEAD (但是您必须强制转换到正确的类型才能访问它们——或者使用访问函数或宏)。
PyObject*
PyObject
PyObject_HEAD
python类型在python类的C中是功能等价的。通过构造新的python类型,可以为python提供新的对象。ndarray对象是在C中定义的新类型的一个示例。新类型在C中通过两个基本步骤定义:
创建C结构(通常命名为 Py{{Name}}Object )它是二进制的-与 PyObject 结构本身,但保留该特定对象所需的附加信息;
Py{{Name}}Object
填充 PyTypeObject 表(由 PyObject 结构)具有指向实现类型所需行为的函数的指针。
PyTypeObject
与定义Python类行为的特殊方法名不同,还有“函数表”指向实现所需结果的函数。自python 2.2以来,pytypeobject本身已经成为动态的,它允许C类型可以从C中的其他C类型“子类型化”,并在python中进行子类化。子类型从其父类型继承属性和方法。
有两种主要的新类型:ndarray( PyArray_Type )和不明飞行物( PyUFunc_Type )其他类型起到支持作用: PyArrayIter_Type , the PyArrayMultiIter_Type 和 PyArrayDescr_Type . 这个 PyArrayIter_Type 是ndarray的平面迭代器的类型(获取平面属性时返回的对象)。这个 PyArrayMultiIter_Type 调用时返回的对象类型 broadcast ()它处理嵌套序列集合上的迭代和广播。此外, PyArrayDescr_Type 是其实例描述数据的数据类型描述符类型。最后,有21个新的标量数组类型,它们是新的python scalar,对应于数组可用的每个基本数据类型。另外还有10种类型是占位符,它们允许数组标量适应实际的Python类型层次结构。
PyArray_Type
PyUFunc_Type
PyArrayIter_Type
PyArrayMultiIter_Type
PyArrayDescr_Type
broadcast
ndarray的python类型是 PyArray_Type . 在C语言中,每个ndarray都是指向 PyArrayObject 结构。此结构的ob_类型成员包含指向 PyArray_Type Type对象。
PyArrayObject
NPY_AO
这个 PyArrayObject C-structure包含数组所需的所有信息。ndarray(及其子类)的所有实例都将具有此结构。为了将来的兼容性,通常应该使用提供的宏访问这些结构成员。如果你需要一个较短的名字,那么你可以利用 NPY_AO (已弃用)定义为等同于 PyArrayObject . 不推荐直接访问结构字段。使用 PyArray_*(arr) 而不是形式。从numpy1.20开始,这个结构的大小不被认为是numpyabi的一部分(参见成员列表末尾的注释)。
PyArray_*(arr)
typedef struct PyArrayObject { PyObject_HEAD char *data; int nd; npy_intp *dimensions; npy_intp *strides; PyObject *base; PyArray_Descr *descr; int flags; PyObject *weakreflist; /* version dependend private members */ } PyArrayObject;
这是所有Python对象都需要的。它至少由一个引用计数成员组成( ob_refcnt )以及指向typeobject的指针( ob_type ). (如果Python是使用特殊选项编译的,那么也可能存在其他元素,有关详细信息,请参见Python源代码树中的Include/object.h)。obu type成员指向Python类型的对象。
ob_refcnt
ob_type
data
可通过 PyArray_DATA ,此数据成员是指向数组第一个元素的指针。这个指针可以(而且通常应该)被重铸为数组的数据类型。
PyArray_DATA
nd
提供此数组的维数的整数。当nd为0时,该数组有时称为秩0数组。这样的数组具有未定义的维度和步长,无法访问。宏 PyArray_NDIM 定义在 ndarraytypes.h 指向此数据成员。 NPY_MAXDIMS 是任何数组的最大维度数。
PyArray_NDIM
ndarraytypes.h
NPY_MAXDIMS
dimensions
一个整数数组,提供每个维度中的形状,长度为nd。 1。整数总是足够大,足以在平台上容纳指针,因此维度大小仅受内存限制。 PyArray_DIMS 是与此数据成员关联的宏。
PyArray_DIMS
strides
一个整数数组,为每个维度提供必须跳过才能到达该维度中下一个元素的字节数。与宏关联 PyArray_STRIDES .
PyArray_STRIDES
base
指向 PyArray_BASE ,此成员用于保存指向与此数组相关的另一个Python对象的指针。有两个用例:
PyArray_BASE
如果这个数组没有自己的内存,那么基点指向拥有它的Python对象(可能是另一个数组对象)
如果此数组具有(已弃用) NPY_ARRAY_UPDATEIFCOPY 或 NPY_ARRAY_WRITEBACKIFCOPY 标志集,则此数组是“行为不正常”数组的工作副本。
NPY_ARRAY_UPDATEIFCOPY
NPY_ARRAY_WRITEBACKIFCOPY
什么时候? PyArray_ResolveWritebackIfCopy 如果调用,则将使用此数组的内容更新基指向的数组。
PyArray_ResolveWritebackIfCopy
descr
指向数据类型描述符对象的指针(见下文)。数据类型描述符对象是一个新的内置类型的实例,它允许内存的通用描述。支持的每种数据类型都有一个描述符结构。此描述符结构包含有关类型的有用信息,以及指向实现特定功能的函数指针表的指针。顾名思义,它与宏相关联 PyArray_DESCR .
PyArray_DESCR
flags
由宏指向 PyArray_FLAGS ,此数据成员表示指示如何解释数据指向的内存的标志。可能的标志是 NPY_ARRAY_C_CONTIGUOUS , NPY_ARRAY_F_CONTIGUOUS , NPY_ARRAY_OWNDATA , NPY_ARRAY_ALIGNED , NPY_ARRAY_WRITEABLE , NPY_ARRAY_WRITEBACKIFCOPY 和 NPY_ARRAY_UPDATEIFCOPY .
PyArray_FLAGS
NPY_ARRAY_C_CONTIGUOUS
NPY_ARRAY_F_CONTIGUOUS
NPY_ARRAY_OWNDATA
NPY_ARRAY_ALIGNED
NPY_ARRAY_WRITEABLE
weakreflist
此成员允许数组对象具有弱引用(使用weakref模块)。
注解
其他成员被认为是私有的和版本相关的。如果结构的大小对代码很重要,则必须特别小心。如果代码依赖于 sizeof(PyArrayObject) 要保持不变,必须在导入时添加以下检查:
sizeof(PyArrayObject)
if (sizeof(PyArrayObject) < PyArray_Type.tp_basicsize) { PyErr_SetString(PyExc_ImportError, "Binary incompatibility with NumPy, must recompile/update X."); return NULL; }
为了确保您的代码不必为特定的NumPy版本编译,您可以添加一个常量,为NumPy中的更改留出空间。一个保证与任何未来NumPy版本兼容的解决方案需要使用运行时计算偏移量和分配大小。
这个 PyArrayDescr_Type 是数据类型描述符对象的内置类型,用于描述如何解释组成数组的字节。静态定义21个 PyArray_Descr 用于内置数据类型的对象。当它们参与引用计数时,它们的引用计数不应达到零。还有一个用户定义的动态表 PyArray_Descr 也被维护的对象。一旦一个数据类型描述符对象被“注册”,它也不应该被释放。函数 PyArray_DescrFromType (…)可用于检索 PyArray_Descr 来自枚举类型号(内置或用户定义)的对象。
PyArray_Descr
PyArray_DescrFromType
这个 PyArray_Descr 结构位于 PyArrayDescr_Type . 虽然这里描述它是为了完整性,但它应该被认为是内部的 NumPy 和操作通过 PyArrayDescr_* 或 PyDataType* 函数和宏。此结构的大小可能会随着numpy版本的不同而变化。为确保兼容性:
PyArrayDescr_*
PyDataType*
从不声明结构的非指针实例
从不执行指针算术
从不使用 sizof(PyArray_Descr)
sizof(PyArray_Descr)
其结构如下:
typedef struct { PyObject_HEAD PyTypeObject *typeobj; char kind; char type; char byteorder; char flags; int type_num; int elsize; int alignment; PyArray_ArrayDescr *subarray; PyObject *fields; PyObject *names; PyArray_ArrFuncs *f; PyObject *metadata; NpyAuxData *c_metadata; npy_hash_t hash; } PyArray_Descr;
typeobj
指向类型对象的指针,该对象是此数组元素对应的python类型。对于内置类型,这将指向相应的数组标量。对于用户定义的类型,这应该指向用户定义的类型对象。此typeobject可以从数组标量继承,也可以不从数组标量继承。如果它不是从数组标量继承的,那么 NPY_USE_GETITEM 和 NPY_USE_SETITEM 标志应设置在 flags 成员。
NPY_USE_GETITEM
NPY_USE_SETITEM
kind
指示数组类型的字符代码(使用数组接口类型字符串表示法)。“b”表示布尔值,“i”表示有符号整数,“u”表示无符号整数,“f”表示浮点值,“c”表示复杂浮点值,“s”表示8位以零结尾的字节,“u”表示32位/字符的Unicode字符串,“v”表示任意值。
type
指示数据类型的传统字符代码。
byteorder
表示字节顺序的字符:“>”(big endian)、“<”(little-endian)、“=”(native)、“”(uncertible,ignore)。所有内置数据类型都具有byteorder“=”。
一个数据类型位标志,用于确定数据类型是否表现出类似于对象数组的行为。此成员中的每个位都是一个标志,其名称为:
NPY_ITEM_REFCOUNT
指示此数据类型的项必须被引用计数(使用 Py_INCREF 和 Py_DECREF )
Py_INCREF
Py_DECREF
NPY_ITEM_HASOBJECT
等同于 NPY_ITEM_REFCOUNT .
NPY_LIST_PICKLE
指示此数据类型的数组必须在酸洗前转换为列表。
NPY_ITEM_IS_POINTER
指示该项是指向其他数据类型的指针
NPY_NEEDS_INIT
指示创建时必须初始化此数据类型的内存(设置为0)。
NPY_NEEDS_PYAPI
指示此数据类型在访问期间需要python c-api(因此,如果需要数组访问,不要放弃gil)。
在阵列访问时使用 f->getitem 函数指针,而不是数组标量的标准转换。如果不定义数组标量与数据类型一起使用,则必须使用。
f->getitem
从数组标量创建0-D数组时,请使用 f->setitem 而不是数组标量的标准副本。如果不定义数组标量与数据类型一起使用,则必须使用。
f->setitem
NPY_FROM_FIELDS
如果在数据类型的任何字段中设置了这些位,则为父数据类型继承的位。目前( NPY_NEEDS_INIT NPY_LIST_PICKLE NPY_ITEM_REFCOUNT NPY_NEEDS_PYAPI )
NPY_OBJECT_DTYPE_FLAGS
为对象数据类型设置的位:( NPY_LIST_PICKLE NPY_USE_GETITEM NPY_ITEM_IS_POINTER NPY_ITEM_REFCOUNT NPY_NEEDS_INIT NPY_NEEDS_PYAPI )
PyDataType_FLAGCHK
如果为数据类型对象设置了所有给定标志,则返回true。
PyDataType_REFCHK
相当于 PyDataType_FLAGCHK ( D型 , NPY_ITEM_REFCOUNT )
type_num
唯一标识数据类型的数字。对于新数据类型,此编号在注册数据类型时分配。
elsize
对于总是大小相同(如long)的数据类型,这将保留数据类型的大小。对于不同数组可以具有不同元素大小的灵活数据类型,此值应为0。
alignment
提供此数据类型的对齐信息的数字。具体来说,它显示了2元素结构(其第一个元素是 char )编译器放置此类型的项: offsetof(struct {{char c; type v;}}, v)
char
offsetof(struct {{char c; type v;}}, v)
subarray
如果这不是 NULL ,则此数据类型描述符是另一个数据类型描述符的C样式连续数组。换句话说,这个描述符描述的每个元素实际上是一些其他基本描述符的数组。对于另一个数据类型描述符中的字段,这是最有用的数据类型描述符。字段成员应为 NULL 如果这不是 NULL (基本描述符的字段成员可以是非- NULL 然而)。
NULL
PyArray_ArrayDescr
typedef struct { PyArray_Descr *base; PyObject *shape; } PyArray_ArrayDescr;
基类型的数据类型描述符对象。
shape
作为python元组的子数组的形状(总是c样式连续)。
fields
如果这不是空值,那么这个数据类型描述符具有由Python字典描述的字段,这些字段的键是名称(如果给定,还包括标题),其值是描述这些字段的元组。回想一下,数据类型描述符总是描述一组固定长度的字节。字段是该固定长度集合的命名子区域。字段由另一个数据类型描述符和字节偏移量组成的元组来描述。或者,元组可以包含通常是Python字符串的标题。这些元组放在这个字典中,按名称键控(如果给定的话还有标题)。
names
字段名的有序元组。如果未定义字段,则为空。
f
指向包含类型需要实现内部功能的函数的结构的指针。这些函数与后面描述的通用函数(UFUNC)不同。他们的签名可以随意更改。
metadata
关于此元数据的数据类型。
c_metadata
特定于特定数据类型的C实现的元数据。为NumPy 1.7.0添加。
npy_hash_t
hash
当前未使用。保留用于将来缓存哈希值。
PyArray_ArrFuncs
实现内部功能的函数。并非所有这些函数指针都必须为给定类型定义。所需的成员是 nonzero , copyswap , copyswapn , setitem , getitem 和 cast . 这些被认为是非- NULL 和 NULL 条目将导致程序崩溃。其他功能可能是 NULL 这就意味着减少了该数据类型的功能。(此外,如果非零函数为 NULL 注册用户定义的数据类型时)。
nonzero
copyswap
copyswapn
setitem
getitem
cast
typedef struct { PyArray_VectorUnaryFunc *cast[NPY_NTYPES]; PyArray_GetItemFunc *getitem; PyArray_SetItemFunc *setitem; PyArray_CopySwapNFunc *copyswapn; PyArray_CopySwapFunc *copyswap; PyArray_CompareFunc *compare; PyArray_ArgFunc *argmax; PyArray_DotFunc *dotfunc; PyArray_ScanFunc *scanfunc; PyArray_FromStrFunc *fromstr; PyArray_NonzeroFunc *nonzero; PyArray_FillFunc *fill; PyArray_FillWithScalarFunc *fillwithscalar; PyArray_SortFunc *sort[NPY_NSORTS]; PyArray_ArgSortFunc *argsort[NPY_NSORTS]; PyObject *castdict; PyArray_ScalarKindFunc *scalarkind; int **cancastscalarkindto; int *cancastto; PyArray_FastClipFunc *fastclip; /* deprecated */ PyArray_FastPutmaskFunc *fastputmask; /* deprecated */ PyArray_FastTakeFunc *fasttake; /* deprecated */ PyArray_ArgFunc *argmin; } PyArray_ArrFuncs;
函数指针的描述中使用了行为段的概念。行为段是一个对齐的段,并按数据类型的本机字节顺序排列。这个 nonzero , copyswap , copyswapn , getitem 和 setitem 函数可以(并且必须)处理行为不正确的数组。其他函数需要行为内存段。
要从当前类型转换为所有其他内置类型的函数指针数组。每个函数都强制转换一个连续的、对齐的和不交换的缓冲区 from 指向一个连续的、对齐的、没有交换的缓冲区 to 要强制转换的项目数由 n 和参数 弗罗马尔 和 托尔 被解释为灵活数组的pyarrayobjects以获取项大小信息。
指向从数组对象的单个元素返回标准python对象的函数的指针。 arr 指向 data . 此函数必须能够正确处理“行为不当”(未对齐和/或交换)数组。
指向设置python对象的函数的指针 item 进入数组, arr ,在指向的位置 data . 此函数用于处理“行为不正常”的数组。如果成功,则返回零,否则返回负的零(以及python错误集)。
这些成员都是指向要从中复制数据的函数的指针 src 到 dest 和 swap 如有指示。arr值仅用于灵活( NPY_STRING , NPY_UNICODE 和 NPY_VOID )数组(从 arr->descr->elsize )第二个函数复制一个值,而第一个函数用提供的步幅循环n个值。这些函数可以处理不当行为 src 数据。如果 src 为空,则不执行任何复制。如果 swap 为0,则不发生字节交换。假设 dest 和 src 不要重叠。如果它们重叠,则使用 memmove (…)先是后是 copyswap(n) 值为空的 src .
NPY_STRING
NPY_UNICODE
NPY_VOID
arr->descr->elsize
memmove
copyswap(n)
src
compare
指向比较数组两个元素的函数的指针, arr 指向 d1 和 d2 . 此函数需要行为(对齐和不交换)的数组。如果 * d1 > * d2 0,如果 * d1 == * d2 和-1如果 * d1 < * d2 . 数组对象 arr 用于检索灵活数组的项大小和字段信息。
arr
d1
d2
argmax
指向函数的指针,该函数检索 n 元素在 arr 从指向的元素开始 data . 此函数要求内存段是连续的并具有行为。返回值始终为0。返回最大元素的索引 max_ind .
n
max_ind
dotfunc
指向将两个数相乘的函数的指针 n -将长度序列加在一起,并将结果放入指向的元素中 op 属于 arr . 两个序列的开头由 ip1 和 ip2 . 要到达每个序列中的下一个元素,需要跳到 is1 和 is2 字节 ,分别。此函数需要行为(尽管不一定是连续的)内存。
op
ip1
ip2
is1
is2
scanfunc
指向函数的指针,该函数从文件描述符扫描(scanf样式)相应类型的一个元素。 fd 指向的数组内存 ip . 假定数组的行为正常。最后一个论点 arr 是要扫描到的阵列。返回成功分配的接收参数数(如果在分配第一个接收参数之前发生匹配失败,则返回0),如果在分配第一个接收参数之前发生输入失败,则返回EOF。应该在不持有Python GIL的情况下调用此函数,并且必须获取它以进行错误报告。
fd
ip
fromstr
指向函数的指针,该函数将指向的字符串转换为 str 对应类型的一个元素,并将其放置在指向的内存位置 ip . 转换完成后, *endptr 指向字符串的其余部分。最后一个论点 arr 是ip点所在的数组(对于可变大小的数据类型是必需的)。成功时返回0,失败时返回-1。需要行为数组。应该在不持有Python GIL的情况下调用此函数,并且必须获取它以进行错误报告。
str
*endptr
指向函数的指针,如果 arr 指向 data 是非零。此函数可以处理行为错误的数组。
fill
指向函数的指针,该函数用数据填充给定长度的连续数组。数组的前两个元素必须已填充。从这两个值中,将计算一个增量,并通过重复添加此计算的增量来计算从项目3到末尾的值。数据缓冲区必须运行良好。
fillwithscalar
指向函数的指针,该函数填充一个连续的 buffer 给定的 length 使用单个标量 value 地址是谁的。最后一个参数是获取可变长度数组的itemsize所需的数组。
buffer
length
value
sort
指向特定排序算法的函数指针数组。一个特殊的排序算法是用一个键(到目前为止 NPY_QUICKSORT , NPY_HEAPSORT 和 NPY_MERGESORT 定义。这些排序是在假定连续和对齐数据的情况下进行的。
NPY_QUICKSORT
NPY_HEAPSORT
NPY_MERGESORT
argsort
指向此数据类型排序算法的函数指针数组。可使用与排序相同的排序算法。产生排序的索引返回到 result (必须用索引0初始化到 length-1 包括在内)。
result
length-1
castdict
要么 NULL 或包含用户定义数据类型的低级强制转换函数的字典。每个函数都包装在 PyCapsule* 并由数据类型编号键入。
PyCapsule*
scalarkind
用于确定应如何解释此类型的标量的函数。论点是 NULL 或者包含数据的0维数组(如果需要确定标量的类型)。返回值的类型必须为 NPY_SCALARKIND .
NPY_SCALARKIND
cancastscalarkindto
要么 NULL 或数组 NPY_NSCALARKINDS 指针。这些指针应该是 NULL 或指向整数数组的指针(以 NPY_NOTYPE )指示可以安全地将指定类型的此数据类型的标量强制转换为的数据类型(这通常意味着不会丢失精度)。
NPY_NSCALARKINDS
NPY_NOTYPE
cancastto
要么 NULL 或整数数组(以 NPY_NOTYPE )指示可以安全地强制转换此数据类型的数据类型(这通常意味着不会丢失精度)。
fastclip
1.17 版后已移除: 使用此函数将在 np.clip . 数据类型必须使用 PyUFunc_RegisterLoopForDescr 将自定义循环附加到 np.core.umath.clip , np.minimum 和 np.maximum .
np.clip
PyUFunc_RegisterLoopForDescr
np.core.umath.clip
np.minimum
np.maximum
1.19 版后已移除: 设置此函数已弃用,应始终禁用 NULL ,如果设置,将忽略它。
一个读取 n_in 项目来自 in 并写入 out 读取值,如果它在 min 和 max 或相应的限制(如果在外部)。内存段必须是连续的且行为良好,并且 min 或 max 可能是 NULL ,但不是两者兼而有之。
n_in
in
out
min
max
fastputmask
接受指针的函数 in 一组数组 n_in 项目,指针 mask 一组数组 n_in 布尔值和指针 vals 一组数组 nv 项目。项目来自 vals 被复制到 in 无论价值在哪里 mask 为非零,平铺 vals 如果需要,如果 nv < n_in . 所有数组都必须是连续的且行为良好。
mask
vals
nv
nv < n_in
fasttake
接受指针的函数 src C连续的行为段,解释为三维形状数组 (n_outer, nindarray, nelem) 一个指针 indarray 到 m_middle 整数索引和指针 dest C连续的行为段,解释为三维形状数组 (n_outer, m_middle, nelem) . 指数 indarray 用于索引 src 沿着第二维度,复制 nelem 项目纳入 dest . clipmode (可以接受值 NPY_RAISE , NPY_WRAP 或 NPY_CLIP )确定小于0或大于0的索引 nindarray 将被处理。
(n_outer, nindarray, nelem)
indarray
m_middle
dest
(n_outer, m_middle, nelem)
nelem
clipmode
NPY_RAISE
NPY_WRAP
NPY_CLIP
nindarray
argmin
指向函数的指针,该函数检索 n 元素在 arr 从指向的元素开始 data . 此函数要求内存段是连续的并具有行为。返回值始终为0。返回最小元素的索引 min_ind .
min_ind
这个 PyArray_Type typeobject实现了 Python objects 包括 tp_as_number , tp_as_sequence , tp_as_mapping 和 tp_as_buffer 接口。这个 rich comparison )还与成员的新样式属性查找一起使用 (tp_members )和属性 (tp_getset )这个 PyArray_Type 也可以是子类型。
Python objects
tp_as_number
tp_as_sequence
tp_as_mapping
tp_as_buffer
rich comparison
tp_members
tp_getset
小技巧
这个 tp_as_number 方法使用泛型方法调用已注册用于处理该操作的任何函数。当 _multiarray_umath module 对于所有的ufs操作,它被导入到数值数组中。此选项可以更改为 PyUFunc_ReplaceLoopBySignature 这个 tp_str 和 tp_repr 方法也可以使用 PyArray_SetStringFunction .
_multiarray_umath module
PyUFunc_ReplaceLoopBySignature
tp_str
tp_repr
PyArray_SetStringFunction
通过创建 PyUFunc_Type . 它是一个非常简单的类型,只实现基本的getattribute行为、打印行为,并且具有允许这些对象像函数一样工作的调用行为。UFUNC背后的基本思想是为支持该操作的每个数据类型保存对快速一维(矢量)循环的引用。这些一维循环都具有相同的签名,并且是创建新UFUNC的关键。它们由通用循环代码调用,以实现N维函数。还有一些为浮动和复杂浮动数组定义的通用一维循环,允许您使用单个标量函数定义UFUNC。( e.g. 阿坦纳)
PyUFuncObject
UFunc的核心是 PyUFuncObject 它包含调用执行实际工作的底层C代码循环所需的所有信息。虽然这里描述它是为了完整性,但它应该被认为是内部的 NumPy 和操作通过 PyUFunc_* 功能。此结构的大小可能会随着numpy版本的不同而变化。为确保兼容性:
PyUFunc_*
从不执行指针运算
从不使用 sizeof(PyUFuncObject)
sizeof(PyUFuncObject)
typedef struct { PyObject_HEAD int nin; int nout; int nargs; int identity; PyUFuncGenericFunction *functions; void **data; int ntypes; int reserved1; const char *name; char *types; const char *doc; void *ptr; PyObject *obj; PyObject *userloops; int core_enabled; int core_num_dim_ix; int *core_num_dims; int *core_dim_ixs; int *core_offsets; char *core_signature; PyUFunc_TypeResolutionFunc *type_resolver; PyUFunc_LegacyInnerLoopSelectionFunc *legacy_inner_loop_selector; PyUFunc_MaskedInnerLoopSelectionFunc *masked_inner_loop_selector; npy_uint32 *op_flags; npy_uint32 *iter_flags; /* new in API version 0x0000000D */ npy_intp *core_dim_sizes; npy_uint32 *core_dim_flags; PyObject *identity_value; } PyUFuncObject;
nin
输入参数的数目。
nout
输出参数的数目。
nargs
参数总数( nin + nout )这个必须小于 NPY_MAXARGS .
NPY_MAXARGS
identity
要么 PyUFunc_One , PyUFunc_Zero , PyUFunc_MinusOne , PyUFunc_None , PyUFunc_ReorderableNone 或 PyUFunc_IdentityValue 以指示此操作的标识。它只用于对空数组进行类似reduce的调用。
PyUFunc_One
PyUFunc_Zero
PyUFunc_MinusOne
PyUFunc_None
PyUFunc_ReorderableNone
PyUFunc_IdentityValue
functions
一个函数指针数组---一个用于ufunc支持的每个数据类型。这是为实现基础函数而调用的向量循环 dims [0] 时代。第一个论点, args ,是一个数组 纳尔格斯 指向行为内存的指针。输入参数的数据指针是第一个,后面是输出参数的数据指针。必须跳过多少字节才能到达序列中的下一个元素由中的相应条目指定 步骤 数组。最后一个参数允许循环接收额外的信息。这是常用的,因此一个通用的向量循环可以用于多个函数。在这种情况下,要调用的实际标量函数作为 超文本 . 此函数指针数组的大小为类型。
要传递给一维向量循环的额外数据,或 NULL 如果不需要额外的数据。此C数组的大小必须相同( i.e. 键入)作为函数数组。 NULL 如果不需要额外的数据,则使用。几个对ufunc的C-API调用只是使用这些额外数据来接收指向要调用的实际函数的指针的一维向量循环。
ntypes
UFUNC支持的数据类型数。这个数字指定有多少不同的一维循环(内置数据类型)可用。
reserved1
未使用的
name
ufunc的字符串名称。它动态地用于构建 __doc__ UFUNC的属性。
types
一个数组 8位类型_号,包含每个受支持(内置)数据类型的函数的类型签名。对于每一个 n型 函数,该数组中相应的一组类型号显示 args 参数应该在一维向量循环中解释。这些类型号不必是同一类型,并且支持混合类型UFunc。
doc
UFUNC文件。不应包含函数签名,因为当 __doc__ 检索。
ptr
任何动态分配的内存。目前,它用于从python函数创建的动态ufunc,以存储类型、数据和名称成员的空间。
obj
对于从python函数动态创建的ufunc,此成员持有对底层python函数的引用。
userloops
用户定义类型的用户定义的一维向量循环(存储为cobject ptrs)的字典。用户可以为任何用户定义的类型注册循环。它是按类型编号检索的。用户定义的类型号始终大于 NPY_USERDEF .
NPY_USERDEF
core_enabled
标量UFunc为0;广义UFunc为1
core_num_dim_ix
签名中不同的核心维度名称数
core_num_dims
每个参数的核心维数
core_dim_ixs
扁平形式的维数索引;参数索引 k 存储在 core_dim_ixs[core_offsets[k] : core_offsets[k] + core_numdims[k]]
k
core_dim_ixs[core_offsets[k] : core_offsets[k] + core_numdims[k]]
core_offsets
每个参数的第一个核心维度的位置 core_dim_ixs ,相当于cumsum (core_num_dims )
core_signature
核心签名字符串
type_resolver
一种函数,它解析类型并用输入和输出的数据类型填充数组。
legacy_inner_loop_selector
返回内部循环的函数。这个 legacy 因为numpy 1.6已经计划了一个更好的变种。这个变种还没有出现。
legacy
reserved2
对于将来可能具有不同签名的循环选择器。
masked_inner_loop_selector
函数,返回ufunc的屏蔽内部循环
op_flags
覆盖每个ufunc操作数的默认操作数标志。
iter_flags
覆盖ufunc的默认nditer标志。
在API版本0x000000D中添加
core_dim_sizes
对于每个不同的核心维度,可能 frozen 大小IF UFUNC_CORE_DIM_SIZE_INFERRED 是 0
UFUNC_CORE_DIM_SIZE_INFERRED
0
core_dim_flags
对于每个不同的核心维度,一组 UFUNC_CORE_DIM* 旗帜
UFUNC_CORE_DIM*
UFUNC_CORE_DIM_CAN_IGNORE
如果dim名称以 ?
?
如果将从操作数而不是从 frozen 签名
identity_value
还原标识,何时 PyUFuncObject.identity 等于 PyUFunc_IdentityValue .
PyUFuncObject.identity
这是一个迭代器对象,它使遍历N维数组变得容易。它是从ndarray的flat属性返回的对象。在整个实现内部,它也被广泛地用于在N维数组上循环。实现了tp_as_映射接口,这样迭代器对象就可以被索引(使用一维索引),并且通过tp_方法表实现了一些方法。这个对象实现了下一个方法,并且可以在迭代程序可以在Python中使用的任何地方使用。
PyArrayIterObject
对应于对象的C结构 PyArrayIter_Type 是 PyArrayIterObject . 这个 PyArrayIterObject 用于跟踪指向n维数组的指针。它包含用于快速遍历数组的相关信息。指针可以通过三种基本方式进行调整:1)以C样式连续方式前进到数组中的“下一个”位置;2)前进到数组中的任意N维坐标;3)前进到数组中的任意一维索引。的成员 PyArrayIterObject 结构用于这些计算。迭代器对象保留自己的维度和数组的步幅信息。这可以根据“广播”的需要进行调整,或者只在特定的维度上循环。
typedef struct { PyObject_HEAD int nd_m1; npy_intp index; npy_intp size; npy_intp coordinates[NPY_MAXDIMS]; npy_intp dims_m1[NPY_MAXDIMS]; npy_intp strides[NPY_MAXDIMS]; npy_intp backstrides[NPY_MAXDIMS]; npy_intp factors[NPY_MAXDIMS]; PyArrayObject *ao; char *dataptr; npy_bool contiguous; } PyArrayIterObject;
nd_m1
在哪里? 是基础数组中的维度数。
index
数组中的当前一维索引。
size
基础数组的总大小。
coordinates
安 -数组中的维度索引。
dims_m1
数组的大小在每个维度中减去1。
阵列的步幅。跳转到每个维度中的下一个元素所需的字节数。
backstrides
需要多少字节才能从维度的结尾跳回到它的开头。注意 backstrides[k] == strides[k] * dims_m1[k] ,但它存储在这里作为优化。
backstrides[k] == strides[k] * dims_m1[k]
factors
此数组用于从一维索引计算n-d索引。它包含所需的尺寸产品。
ao
指向此迭代器创建用于表示的基础ndarray的指针。
dataptr
此成员指向由索引指示的ndarray中的元素。
contiguous
如果基础数组是 NPY_ARRAY_C_CONTIGUOUS . 它用于尽可能简化计算。
如何在C级上使用数组迭代器将在后面的章节中更详细地解释。通常,您不需要关心迭代器对象的内部结构,只需要通过使用宏与它进行交互。 PyArray_ITER_NEXT (它) PyArray_ITER_GOTO (IT,DEST),或 PyArray_ITER_GOTO1D (IT,索引)。所有这些宏都需要参数 it 成为一个 PyArrayIterObject* .
PyArray_ITER_NEXT
PyArray_ITER_GOTO
PyArray_ITER_GOTO1D
PyArrayIterObject*
这种类型提供了一个迭代器,它封装了广播的概念。它允许 要一起广播的数组,以便循环在广播的数组上以C样式的连续方式进行。相应的C结构是 PyArrayMultiIterObject 其内存布局必须以任何对象开头, obj ,传递给 PyArray_Broadcast (obj)功能。通过调整数组迭代器来执行广播,以便每个迭代器表示广播的形状和大小,但调整其步幅,以便在每次迭代中使用数组中的正确元素。
PyArrayMultiIterObject
PyArray_Broadcast
typedef struct { PyObject_HEAD int numiter; npy_intp size; npy_intp index; int nd; npy_intp dimensions[NPY_MAXDIMS]; PyArrayIterObject *iters[NPY_MAXDIMS]; } PyArrayMultiIterObject;
numiter
需要广播到同一形状的数组数。
广播的总大小。
广播结果中的当前(一维)索引。
广播结果中的维度数。
广播结果的形状(仅 nd 使用插槽)。
iters
一个迭代器对象数组,用于保存迭代器以便将数组一起广播。返回时,迭代器被调整为广播。
PyArrayNeighborhoodIter_Type
这是一个迭代器对象,它使得在n维邻域上循环变得容易。
PyArrayNeighborhoodIterObject
对应于对象的C结构 PyArrayNeighborhoodIter_Type 是 PyArrayNeighborhoodIterObject .
typedef struct { PyObject_HEAD int nd_m1; npy_intp index, size; npy_intp coordinates[NPY_MAXDIMS] npy_intp dims_m1[NPY_MAXDIMS]; npy_intp strides[NPY_MAXDIMS]; npy_intp backstrides[NPY_MAXDIMS]; npy_intp factors[NPY_MAXDIMS]; PyArrayObject *ao; char *dataptr; npy_bool contiguous; npy_intp bounds[NPY_MAXDIMS][2]; npy_intp limits[NPY_MAXDIMS][2]; npy_intp limits_sizes[NPY_MAXDIMS]; npy_iter_get_dataptr_t translate; npy_intp nd; npy_intp dimensions[NPY_MAXDIMS]; PyArrayIterObject* _internal_iter; char* constant; int mode; } PyArrayNeighborhoodIterObject;
PyArrayFlags_Type
从python中检索flags属性时,将构造此类型的特殊内置对象。这种特殊的类型通过将不同的标志作为属性访问,或者像对象是一个字典一样将标志名作为条目访问,使得使用不同的标志更加容易。
PyArrayFlagsObject
typedef struct PyArrayFlagsObject { PyObject_HEAD PyObject *arr; int flags; } PyArrayFlagsObject;
对于数组中可能存在的每种不同的内置数据类型,都有一个python类型,其中大多数都是简单的包装器,围绕C中相应的数据类型。这些类型的C名称是 Py{{TYPE}}ArrType_Type 在哪里? {{TYPE}} 可以是
Py{{TYPE}}ArrType_Type
{{TYPE}}
Bool , Byte , 短 , Int , Long , LongLong , UByte , UShort , UInt , ULong , ULongLong , Half , 浮标 , 双重的 , LongDouble , CFloat , CDouble , CLongDouble , 弦 , 统一码 , Void 和 对象 .
这些类型名是C-API的一部分,因此可以在扩展C代码中创建。还有一个 PyIntpArrType_Type 和A PyUIntpArrType_Type 这是可以在平台上保存指针的整数类型之一的简单替换。这些标量对象的结构不向C代码公开。函数 PyArray_ScalarAsCtype (..)可用于从数组标量和函数中提取C类型值 PyArray_Scalar (…)可用于从C值构造数组标量。
PyIntpArrType_Type
PyUIntpArrType_Type
PyArray_ScalarAsCtype
PyArray_Scalar
一些新的C结构被发现在numpy的开发中是有用的。这些C结构至少在一个C-API调用中使用,因此在这里进行了记录。定义这些结构的主要原因是为了便于使用python parsetuple C-api将python对象转换为有用的C对象。
PyArray_Dims
当需要解释形状和/或步幅信息时,此结构非常有用。结构为:
typedef struct { npy_intp *ptr; int len; } PyArray_Dims;
这个结构的成员是
指向列表的指针 (npy_intp )通常表示数组形状或数组步幅的整数。
npy_intp
len
整数列表的长度。假定进入安全 ptr [0] 到 ptr [len-1] .
PyArray_Chunk
这相当于python中的缓冲区对象结构,直到ptr成员为止。在32位平台上( i.e. 如果 NPY_SIZEOF_INT = NPY_SIZEOF_INTP ,len成员还与缓冲区对象的等效成员匹配。表示通用的单段内存块很有用。
NPY_SIZEOF_INT
NPY_SIZEOF_INTP
typedef struct { PyObject_HEAD PyObject *base; void *ptr; npy_intp len; int flags; } PyArray_Chunk;
成员是
这个内存块来自的python对象。需要这样才能正确地计算内存。
指向单段内存块开头的指针。
段的长度(字节)。
任何数据标志( e.g. NPY_ARRAY_WRITEABLE )这应该用来解释记忆。
参见
数组接口
PyArrayInterface
这个 PyArrayInterface 结构的定义使得numpy和其他扩展模块可以使用快速阵列接口协议。这个 __array_struct__ 支持快速数组接口协议的对象的方法应返回 PyCapsule 包含指向 PyArrayInterface 具有数组的相关详细信息的结构。创建新数组后,属性应为 DECREF D,它将释放 PyArrayInterface 结构。记住 INCREF 对象(其 __array_struct__ 属性)并指向新的 PyArrayObject 到同一个对象。这样就可以正确管理阵列的内存。
__array_struct__
PyCapsule
DECREF
INCREF
typedef struct { int two; int nd; char typekind; int itemsize; int flags; npy_intp *shape; npy_intp *strides; void *data; PyObject *descr; } PyArrayInterface;
two
整数2作为健全性检查。
数组中的维度数。
typekind
一种字符,根据typestring约定,用“t”->位字段、“b”->布尔值、“i”->有符号整数、“u”->无符号整数、“f”->浮点、“c”->复杂浮点、“o”->对象、“s”->(byte)字符串、“u”->unicode、“v”->void指示存在哪种类型的数组。
itemsize
数组中每个项所需的字节数。
任何比特 NPY_ARRAY_C_CONTIGUOUS (1) NPY_ARRAY_F_CONTIGUOUS (2) NPY_ARRAY_ALIGNED (0x100) NPY_ARRAY_NOTSWAPPED (0x200),或 NPY_ARRAY_WRITEABLE (0x400)指示有关数据的内容。这个 NPY_ARRAY_ALIGNED , NPY_ARRAY_C_CONTIGUOUS 和 NPY_ARRAY_F_CONTIGUOUS 标志实际上可以从其他参数中确定。旗 NPY_ARR_HAS_DESCR (0x800)也可以设置为指示使用版本3数组接口的对象存在结构的DESCR成员(使用版本2数组接口的对象将忽略该成员)。
NPY_ARRAY_NOTSWAPPED
NPY_ARR_HAS_DESCR
包含每个维度中数组大小的数组。
包含要跳转到每个维度中的下一个元素的字节数的数组。
指针 to 数组的第一个元素。
更详细地描述数据类型的python对象(与 德克思 键入 __array_interface__ )这可以 NULL 如果 类型 和 项目尺寸 提供足够的信息。此字段也将被忽略,除非 NPY_ARR_HAS_DESCR 标志在 旗帜 .
__array_interface__
在内部,代码主要使用一些额外的python对象进行内存管理。这些类型不能直接从Python访问,也不能公开给C-API。这里包含它们只是为了完整性和帮助理解代码。
PyUFuncLoopObject
包含循环所需信息的C结构的松散包装。如果您试图理解ufunc循环代码,这很有用。这个 PyUFuncLoopObject 是相关的C结构。它在 ufuncobject.h 标题。
ufuncobject.h
PyUFuncReduceObject
一种C结构的松散包装物,其中包含了UFUNC的类还原方法所需的信息。如果您试图理解代码的reduce、accumulate和reduce,这是很有用的。这个 PyUFuncReduceObject 是相关的C结构。它在 ufuncobject.h 标题。
PyUFunc_Loop1d
一个简单的C结构链接列表,其中包含为用户定义数据类型的每个已定义签名为UFUNC定义一维循环所需的信息。
PyArrayMapIter_Type
高级索引是用这种python类型处理的。它只是一个围绕C结构的松散包装,其中包含高级数组索引所需的变量。相关的C-结构, PyArrayMapIterObject ,对于试图理解高级索引映射代码很有用。它在 arrayobject.h 标题。此类型不向Python公开,可以用C结构替换。作为一种python类型,它利用了引用计数内存管理。
PyArrayMapIterObject
arrayobject.h