数组接口

注意

本页面描述了用于从其他C扩展访问numpy数组内容的numpy专用API。PEP 3118The 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(可选)

元组列表提供了对同类阵列中每个项目的内存布局更详细的描述。列表中的每个元组都有两个或三个元素。通常,当typestrV[0-9]+时将使用此属性,但这不是必需条件。唯一的要求是typestr键中表示的字节数与此处表示的总字节数相同。这个想法是支持构成数组元素的类C结构的描述。列表中每个元组的元素都是

  1. 一个字符串,提供与这部分数据类型关联的名称。这也可以是('full name', 'basic_name')的元组,其中基本名称是表示字段全名的有效Python变量名称。
  2. 无论是typestr中的基本类型描述字符串还是另一个列表(用于嵌套结构化类型)
  3. 一个可选的形状元组,提供该结构的这部分应重复多少次。如果没有给出,则不假定重复。使用这个通用接口可以描述非常复杂的结构。但是请注意,数组中的每个元素仍然是相同的数据类型。下面给出了使用这个接口的一些例子。

默认[('', typestr)]

数据(可选)

一个2元组,其第一个参数是一个指向存储数组内容的数据区域的整数(必要时为长整数)。这个指针必须指向数据的第一个元素(换句话说,在这种情况下,任何偏移总是被忽略)。元组中的第二个条目是只读标志(true表示数据区域是只读的)。

该属性也可以是暴露将用于共享数据的buffer interface的对象。如果该键不存在(或返回None),则共享内存将通过对象本身的缓冲区接口完成。在这种情况下,偏移键可用于指示缓冲区的开始。如果要保护内存区域,则必须通过新对象存储暴露阵列接口的对象的引用。

默认None

步幅(可选)

可以用None来表示一个C样式的连续数组或一个stride元组,它提供了跳转到相应维度中的下一个数组元素所需的字节数。每个条目必须是一个整数(一个Python intlong)。与形状一样,这些值可能大于可以用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界面非常相似。差异主要是审美。尤其是:

  1. PyArrayInterface结构在最后没有descr成员(因此没有标志ARR_HAS_DESCR)
  2. 没有指定从__array_struct__返回的PyCObject的desc成员。通常,它是暴露数组的对象(因此当C对象被销毁时,它的引用可以被保留和销毁)。现在它必须是一个元组,其第一个元素是一个带有“PyArrayInterface Version#”的字符串,第二个元素是暴露该数组的对象。
  3. 从__array_interface __ ['data']返回的元组曾经是一个十六进制字符串(现在是一个整数或一个长整数)。
  4. 没有__array_interface__属性,而__array_interface__字典中的所有键(除了版本)都是它们自己的属性:因此,要获取Python端信息,必须单独访问属性:
    • __array_data__
    • __array_shape__
    • __array_strides__
    • __array_typestr__
    • __array_descr__
    • __array_offset__
    • __array_mask__