数组接口¶
注意
本页面描述了用于从其他C扩展访问numpy数组内容的numpy专用API。PEP 3118 – The Revised Buffer Protocol
introduces similar, standardized API to Python 2.6 and 3.0 for any extension module to use. Cython‘s buffer array support uses the PEP 3118 API; see the Cython numpy tutorial. Cython提供了一种编写支持Python版本低于2.6的缓冲协议的代码的方法,因为它具有使用此处描述的阵列接口的向后兼容实现。
版: | 3 |
---|
数组接口(有时称为数组协议)是在2005年创建的,它可以让类似数组的Python对象尽可能智能地重用对方的数据缓冲区。均匀的N维数组接口是对象共享N维数组内存和信息的默认机制。该接口由一个Python端和一个使用两个属性的C端组成。希望在应用程序代码中被视为N维数组的对象应该至少支持其中一个属性。希望在应用程序代码中支持N维数组的对象应至少查找其中一个属性并使用适当提供的信息。
这个接口描述了齐次数组,因为数组中的每一项都具有相同的“类型”。这种类型可以非常简单,也可以是一个相当随意而复杂的类C结构。
有两种使用接口的方法:Python方和C方。两者都是独立的属性。
Python方面¶
这种接口方法由具有__array_interface__
属性的对象组成。
-
__array_interface__
¶ 项目词典(需要3个,可选5个)。如果没有提供,字典中的可选键暗含默认值。
关键是:
形状(必填)
元组的元素是每个维度中的数组大小。每个条目都是一个整数(一个Python int或long)。请注意,这些整数可能比平台“int”或“long”可能容纳的大(Python int是C long)。这取决于使用这个属性的代码来适当地处理这个问题;当可能发生溢出时引发错误,或者使用Py_LONG_LONG
作为形状的C类型。typestr(必填)
A string providing the basic type of the homogenous array The basic string format consists of 3 parts: a character describing the byteorder of the data (
<
: little-endian,>
: big-endian,|
: not-relevant), a character code giving the basic type of the array, and an integer providing the number of bytes the type uses.基本类型字符代码是:
t
位字段(以下整数给出位字段中的位数)。 b
布尔值(整数类型,其中所有值仅为True或False) i
整数 u
无符号整数 f
浮点 c
复杂的浮点数 m
Timedelta M
约会时间 O
对象(即内存包含一个指向 PyObject
的指针)S
字符串(字符的固定长度序列) U
Unicode( Py_UNICODE
的固定长度序列)V
其他(void * - 每个项目都是固定大小的内存块) descr(可选)
元组列表提供了对同类阵列中每个项目的内存布局更详细的描述。列表中的每个元组都有两个或三个元素。通常,当typestr为
V[0-9]+
时将使用此属性,但这不是必需条件。唯一的要求是typestr键中表示的字节数与此处表示的总字节数相同。这个想法是支持构成数组元素的类C结构的描述。列表中每个元组的元素都是- 一个字符串,提供与这部分数据类型关联的名称。这也可以是
('full name', 'basic_name')
的元组,其中基本名称是表示字段全名的有效Python变量名称。 - 无论是typestr中的基本类型描述字符串还是另一个列表(用于嵌套结构化类型)
- 一个可选的形状元组,提供该结构的这部分应重复多少次。如果没有给出,则不假定重复。使用这个通用接口可以描述非常复杂的结构。但是请注意,数组中的每个元素仍然是相同的数据类型。下面给出了使用这个接口的一些例子。
默认:
[('', typestr)]
数据(可选)
一个2元组,其第一个参数是一个指向存储数组内容的数据区域的整数(必要时为长整数)。这个指针必须指向数据的第一个元素(换句话说,在这种情况下,任何偏移总是被忽略)。元组中的第二个条目是只读标志(true表示数据区域是只读的)。
该属性也可以是暴露将用于共享数据的
buffer interface
的对象。如果该键不存在(或返回None
),则共享内存将通过对象本身的缓冲区接口完成。在这种情况下,偏移键可用于指示缓冲区的开始。如果要保护内存区域,则必须通过新对象存储暴露阵列接口的对象的引用。默认:
None
步幅(可选)
可以用
None
来表示一个C样式的连续数组或一个stride元组,它提供了跳转到相应维度中的下一个数组元素所需的字节数。每个条目必须是一个整数(一个Pythonint
或long
)。与形状一样,这些值可能大于可以用C“int”或“long”表示的值;调用代码应该通过引发错误或者在C中使用Py_LONG_LONG
来正确处理这个问题。缺省值是None
,这意味着C风格的连续内存缓冲区。在这个模型中,阵列的最后一个维度变化最快。例如,数组条目长度为8个字节,形状为(10,20,30)的对象的默认大小为(4800,240,8)默认:
None
(C风格连续)掩码(可选)
None
or an object exposing the array interface. 掩码数组的所有元素只能解释为true或不正确,表示该数组的哪些元素是有效的。这个对象的形状应该是“broadcastable”到原始数组的形状。默认:
None
(所有数组值均有效)偏移量(可选)
一个整数偏移到数组数据区域。这只能在数据
None
或返回buffer
对象时使用。默认:0。
版本(必填)
显示接口版本的整数(即此版本的3)。小心不要使用这个来使对象暴露未来版本的接口失效。- 一个字符串,提供与这部分数据类型关联的名称。这也可以是
C结构访问¶
对数组接口的这种方法只允许使用一个属性查找和定义良好的C结构来更快地访问数组。
-
__array_struct__
¶ A:c:type:PyCObject,它的
voidptr
成员包含指向填充的PyArrayInterface
结构的指针。该结构的内存是动态创建的,并且PyCObject
也是使用适当的析构函数创建的,所以此属性的检索器只需将Py_DECREF
应用于此属性返回的对象它完成了。此外,无论是需要将数据复制出来,还是必须保留对暴露此属性的对象的引用,以确保数据不会被释放。暴露__array_struct__
接口的对象如果其他对象引用它们,也不能重新分配它们的内存。
PyArrayInterface结构在numpy/ndarrayobject.h
中定义为:
typedef struct {
int two; /* contains the integer 2 -- simple sanity check */
int nd; /* number of dimensions */
char typekind; /* kind in array --- character code of typestr */
int itemsize; /* size of each element */
int flags; /* flags indicating how the data should be interpreted */
/* must set ARR_HAS_DESCR bit to validate descr */
Py_intptr_t *shape; /* A length-nd array of shape information */
Py_intptr_t *strides; /* A length-nd array of stride information */
void *data; /* A pointer to the first element of the array */
PyObject *descr; /* NULL or data-description (same as descr key
of __array_interface__) -- must set ARR_HAS_DESCR
flag or this will be ignored. */
} PyArrayInterface;
标志成员可以由5位组成,显示应该如何解释数据,以及一位显示如何解释接口。The data-bits are CONTIGUOUS
(0x1), FORTRAN
(0x2), ALIGNED
(0x100), NOTSWAPPED
(0x200), and WRITEABLE
(0x400). 最终标志ARR_HAS_DESCR
(0x800)指示此结构是否具有arrdescr字段。除非此标志存在,否则不应访问该字段。
自2006年6月16日起新增:
在过去,大多数实现都使用PyCObject
本身的“desc”成员(不要将它与上面的PyArrayInterface
结构的“descr”成员相混淆 - 它们是两个独立的东西)来保存指向暴露接口的对象的指针。这现在是界面的明确部分。当使用PyCObject_FromVoidPtrAndDesc
创建PyCObject
时,一定要拥有对该对象的引用。
类型描述示例¶
为了清楚起见,提供类型描述和相应的__array_interface__
'descr'条目的一些例子是有用的。感谢Scott Gilbert提供的这些例子:
在任何情况下,“descr”键都是可选的,但当然会提供更多的信息,这些信息对于各种应用程序可能很重要:
* Float data
typestr == '>f4'
descr == [('','>f4')]
* Complex double
typestr == '>c8'
descr == [('real','>f4'), ('imag','>f4')]
* RGB Pixel data
typestr == '|V3'
descr == [('r','|u1'), ('g','|u1'), ('b','|u1')]
* Mixed endian (weird but could happen).
typestr == '|V8' (or '>u8')
descr == [('big','>i4'), ('little','<i4')]
* Nested structure
struct {
int ival;
struct {
unsigned short sval;
unsigned char bval;
unsigned char cval;
} sub;
}
typestr == '|V8' (or '<u8' if you want)
descr == [('ival','<i4'), ('sub', [('sval','<u2'), ('bval','|u1'), ('cval','|u1') ]) ]
* Nested array
struct {
int ival;
double data[16*4];
}
typestr == '|V516'
descr == [('ival','>i4'), ('data','>f8',(16,4))]
* Padded structure
struct {
int ival;
double dval;
}
typestr == '|V16'
descr == [('ival','>i4'),('','|V4'),('dval','>f8')]
应该清楚的是,任何结构化类型都可以使用这个接口来描述。
与数组接口(版本2)的差异¶
版本2界面非常相似。差异主要是审美。尤其是:
- PyArrayInterface结构在最后没有descr成员(因此没有标志ARR_HAS_DESCR)
- 没有指定从__array_struct__返回的PyCObject的desc成员。通常,它是暴露数组的对象(因此当C对象被销毁时,它的引用可以被保留和销毁)。现在它必须是一个元组,其第一个元素是一个带有“PyArrayInterface Version#”的字符串,第二个元素是暴露该数组的对象。
- 从__array_interface __ ['data']返回的元组曾经是一个十六进制字符串(现在是一个整数或一个长整数)。
- 没有__array_interface__属性,而__array_interface__字典中的所有键(除了版本)都是它们自己的属性:因此,要获取Python端信息,必须单独访问属性:
- __array_data__
- __array_shape__
- __array_strides__
- __array_typestr__
- __array_descr__
- __array_offset__
- __array_mask__