The Array Interface

原文:https://docs.scipy.org/doc/numpy/reference/arrays.interface.html

译者:飞龙 UsyiyiCN

校对:(虚位以待)

注意

本页描述了用于从其他C扩展访问numpy数组的内容的numpy特定API。 PEP 3118 - The Revised Buffer Protocol向Python 2.6和3.0引入类似的标准化API,以便使用任何扩展模块。Cython的缓冲区数组支持使用 PEP 3118 API;请参阅Cython numpy教程Cython提供了一种编写代码的方法,该代码支持使用2.6以前的Python版本的缓冲区协议,因为它有一个使用这里描述的数组接口的向后兼容的实现。

版:3

数组接口(有时称为数组协议)是在2005年创建的,作为数组类Python对象的一种手段,在可能的情况下智能重用对方的数据缓冲区。同构N维数组接口是对象共享N维数组存储器和信息的默认机制。该接口由一个Python端和一个C端使用两个属性组成。希望在应用程序代码中被视为N维数组的对象应当支持这些属性中的至少一个。希望在应用程序代码中支持N维数组的对象应该查找这些属性中的至少一个并使用适当提供的信息。

此接口描述同质数组,在数组的每个项目具有相同的“类型”的意义上。这种类型可以非常简单,或者它可以是相当任意和复杂的C样结构。

有两种方式使用接口:Python端和C端。两者都是单独的属性。

Python side

这种接口方法由具有__array_interface__属性的对象组成。

__array_interface__

项目字典(需要3个,可选5个)。如果未提供字典中的可选键,则默认值为默认值。

键是:

形状(必填)

元组是每个维中的数组大小的元组。每个条目是一个整数(Python int或long)。注意,这些整数可能比平台“int”或“long”可能更大(Python int是C长)。它取决于使用此属性的代码适当地处理这个属性;或者通过使用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 Boolean(整数类型,其中所有值只有True或False)
i 整数
u 无符号整数
f 浮点
c 复杂浮点
m Timedelta
M 约会时间
O 对象(即内存包含指向PyObject的指针)
S 字符串(char的固定长度序列)
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样式连续数组或提供跳转到相应维中下一个数组所需的字节数的步长的元组。每个条目必须是整数(Python intlong)。与形状一样,值可以大于可以由C“int”或“long”表示的值;调用代码应该通过提高错误或使用C中的Py_LONG_LONG来适当地处理这个错误。默认是None,这意味着一个C型连续内存缓冲区。在此模型中,数组的最后一个维度变化最快。例如,对于其数组条目长度为8个字节且形状为(10,20,30)的对象的默认步长元组将为(4800,240,8)

默认None(C样式连续)

掩码(可选)

None或暴露数组界面的对象。掩码数组的所有元素应仅解释为true或不为true,表示此数组的哪些元素有效。此对象的形状应为“broadcastable”到原数字组的形状。

默认None(所有数组的值都有效)

偏移(可选)

到数组数据区域的整数偏移量。这只能在数据None或返回buffer对象时使用。

默认:0。

版本(必填)

显示界面版本的整数(即此版本的3)。注意不要使用此操作来使展示未来版本的界面的对象无效。

C-struct access

对于数组接口的这种方法允许仅使用一个属性查找和良好定义的C结构来更快地访问数组。

__array_struct__

A:c:type:PyCObjectvoidptr成员包含指向填充的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位组成,表示如何解释数据,一位示出如何解释接口。数据位为CONTIGUOUS(0x1),FORTRAN(0x2),ALIGNED(0x100),NOTSWAPPED 0x200)和WRITEABLE(0x400)。最终标志ARR_HAS_DESCR(0x800)指示此结构是否具有arrdescr字段。除非该标志存在,否则不应访问该字段。

2006年6月16日新增:

在过去,大多数实现使用PyCObject本身的“desc”成员(不要将其与上面PyArrayInterface结构的“descr”成员混淆 - 事物)来保持指向暴露接口的对象的指针。这现在是接口的一个明确的部分。当使用PyCObject_FromVoidPtrAndDesc创建PyCObject时,请确保拥有对对象的引用。

Type description examples

为了清楚起见,提供类型描述和对应的__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')]

应该清楚的是,任何结构化类型都可以使用这个接口来描述。

Differences with Array interface (Version 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__