数组接口

注解

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

version:3

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

这个接口描述了同构数组,即数组的每一项都具有相同的类型。 这种类型可以非常简单,也可以是一个非常任意和复杂的C类结构

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

Python 方面

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

__array_interface__

字典项(3项必须,5项可选)。如果不提供可选键,则字典中的可选键具有隐含的默认值。

这些键是:

shape (必须)

元组,其元素是每个维度中的数组大小。每个条目都是一个整数(Python、int或Long)。 请注意,这些整数可能大于平台 intLong 所能容纳的大小(Python的int是C的long)。 这取决于使用此属性的代码来适当地处理此问题;可以在可能发生溢出时引发错误, 也可以使用 Py_LONG_LONG G作为形状的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 (所有值都为真或假的整数类型)
i Integer
u Unsigned integer
f Floating point
c Complex floating point
m Timedelta
M Datetime
O Object (内存包含指向 PyObject 的指针)
S String (char 定长序列)
U Unicode (Py_UNICODE 定长序列)
V Other (void * – 每个项都是一个固定大小的内存块)

descr (可选)

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

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

Default: [('', typestr)]

data (可选)

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

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

Default: None

strides (可选)

None 表示C风格的连续数组或步长元组,它提供跳转到相应维度中下一个数组元素所需的字节数。 每个条目必须是一个整数(Python intlong )。与形状一样,这些值可能比用C intlong ` 表示的值要大;调用代码应该通过引发错误或在C中使用 :c:type:`Py_LONG_LONG 来适当地处理这一问题。 缺省值为 None ,这意味着C风格的连续内存缓冲区。在这个模型中,数组的最后一个维度变化最快。 例如,对于数组条目长度为8个字节且形状为(10,20,30)的对象的默认步长元组将为(4800,240,8)

Default: None (C-style contiguous)

mask (可选)

None 或暴露数组接口的对象。 掩码数组的所有元素应仅解释为true或不为true, 指示此数组的哪些元素有效。 该对象的形状应该是`”可广播” <arrays.broadcasting.broadcastable>`到原始数组的形状。

Default: None (All array values are valid)

offset (可选)

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

Default: 0.

version (required)

显示接口版本的整数(此版本为3)。 注意不要使用它来使暴露未来版本的接口的对象无效。

C结构的访问

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

__array_struct__

: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) 指示该结构是否有 arrdesr 字段。 除非出现此标志,否则不应访问该字段。

2006年6月16日以来的新特性:

在过去,大多数实现使用 PyCObject 本身的 desc 成员来保存指向暴露接口的对象的指针 (不要将其与上面 PyArrayInterface 结构的 descr 成员混淆-它们是两个独立的东西) 这现在是接口的显式部分。当使用 PyCObject_FromVoidPtrAndDesc 创建 PyCObject 时,请确保拥有对该对象的引用。

类型描述实例

为清楚起见,提供类型描述和相应的 __array_interface__ ‘descr’条目的 一些示例是有用的。

在每种情况下,’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')]

It should be clear that any structured type could be described using this interface.

与Array接口(版本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__