数组接口

注解

本页介绍用于从其他C扩展访问numpy数组内容的numpy特定API。 PEP 3118 —— The Revised Buffer Protocol 为任何要使用的扩展模块引入与python 2.6和3.0类似的标准化API。Cython_uuuuuuuu的缓冲区数组支持使用 PEP 3118 API;参见 `Cython numpy tutorial`_ ②Cython提供了一种编写代码的方法,该代码支持Python版本早于2.6的缓冲区协议,因为它有一个使用此处描述的数组接口的向后兼容实现。

版本

3

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

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

使用接口有两种方法:一种是Python端,另一种是C端。两者都是单独的属性。

Python 侧

该接口方法由具有 __array_interface__ 属性。

object.__array_interface__

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

关键是:

形状 (需要)

其元素是每个维度中数组大小的元组。每个条目都是一个整数(Python int ). 请注意,这些整数可能大于平台 intlong 能容纳( Python ) int 是C long ). 由使用此属性的代码来适当地处理此问题;或者在可能发生溢出时引发错误,或者使用 long long 作为形状的C类型。

打字机 (需要)

提供同构数组基本类型的字符串基本字符串格式由3部分组成:描述数据字节顺序的字符 (< :小endian, > 大端 | :不相关),提供数组基本类型的字符代码,以及提供类型使用的字节数的整数。

基本类型字符代码为:

t

位字段(后面的整数给出位字段中的位数)。

b

布尔值(所有值都是真或假的整数类型)

i

整数

u

无符号整数

f

浮点

c

复杂浮点

m

时间增量

M

日期时间

O

对象(即内存包含指向 PyObject

S

字符串(固定长度字符序列)

U

Unicode(固定长度序列 Py_UNICODE

V

其他(无效) * --每个项目都是固定大小的内存块)

德克思 (可选)

元组列表,为同类数组中的每个项提供更详细的内存布局描述。列表中的每个元组都有两个或三个元素。通常,当 打字机V[0-9]+ 但这不是要求。唯一的要求是 打字机 键与此处表示的字节总数相同。其思想是支持组成数组元素的类C结构的描述。列表中每个元组的元素是

  1. 提供与此数据类型部分关联的名称的字符串。这也可以是一个 ('full name', 'basic_name') 其中,basic name将是表示字段全名的有效python变量名。

  2. 基本类型描述字符串 打字机 或其他列表(对于嵌套结构类型)

  3. 一个可选的形状元组,提供该结构部分应重复的次数。如果未给出,则不假定重复。使用这个通用接口可以描述非常复杂的结构。但是,请注意,数组中的每个元素仍然是相同的数据类型。下面给出了一些使用这个接口的例子。

违约[('', typestr)]

data (可选)

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

此属性也可以是一个对象,它公开 buffer interface 将用于共享数据。如果这个键不存在(或者返回None),那么内存共享将通过对象本身的缓冲区接口完成。在这种情况下,offset键可用于指示缓冲区的开始。如果要保护内存区域,对暴露数组接口的对象的引用必须由新对象存储。

违约 没有

大步 (可选)

要么 None 指示C样式的连续数组或步幅元组,该数组或步幅元组提供跳转到相应维度中的下一个数组元素所需的字节数。每个条目必须是一个整数(一个python int ). 与shape一样,这些值可能比C表示的值大 intlong 通过调用或适当地使用 long long 在C中,默认值为 None 这意味着一个C风格的连续内存缓冲区。在这个模型中,数组的最后一个维度变化最快。例如,对于数组条目长度为8字节且形状为 (10, 20, 30) 将是 (4800, 240, 8)

违约None (C型相邻)

mask (可选)

无对象或暴露数组接口的对象。掩码数组的所有元素应仅解释为true或not true,以指示此数组的哪些元素有效。应该是这个物体的形状 "broadcastable" 到原始数组的形状。

违约 :无(所有数组值都有效)

抵消 (可选)

数组数据区域的整数偏移量。仅当数据为 None 或返回 buffer 对象。

违约 0。

版本 (需要)

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

C结构访问

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

object.__array_struct__

A PyCapsule 谁的 pointer 成员包含指向已填充的 PyArrayInterface 结构。该结构的内存是动态创建的,并且 PyCapsule 也使用适当的析构函数创建,因此该属性的检索器只需应用 Py_DECREF 此属性完成后返回的对象。另外,要么需要复制数据,要么必须保留对公开此属性的对象的引用,以确保数据不会被释放。对象显示 __array_struct__ 如果其他对象正在引用它们,接口也不能重新分配它们的内存。

这个 PyArrayInterface 结构在中定义 numpy/ndarrayobject.h AS::

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;

flags成员可以由5位组成,显示数据应如何解释,一位显示接口应如何解释。数据位是 NPY_ARRAY_C_CONTIGUOUS (0x1) NPY_ARRAY_F_CONTIGUOUS (0x2) NPY_ARRAY_ALIGNED (0x100) NPY_ARRAY_NOTSWAPPED (0x200),以及 NPY_ARRAY_WRITEABLE (0x400)。最后的旗帜 NPY_ARR_HAS_DESCR (0x800)指示此结构是否具有arrdescr字段。除非存在此标志,否则不应访问该字段。

NPY_ARR_HAS_DESCR

2006年6月16日起新增:

在过去,大多数实现都使用 desc 会员 PyCObject (现在) PyCapsule )本身(不要将其与 PyArrayInterface 结构——它们是两个独立的东西)来保持指向暴露接口的对象的指针。这现在是接口的显式部分。确保引用对象并调用 PyCapsule_SetContext 在归还之前 PyCapsule ,并配置析构函数以取消引用此引用。

类型描述示例

为了清晰起见,提供一些类型描述和相应的 __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标志有descr)

  2. 这个 context 会员 PyCapsule (正式声明) desc 会员 PyCObject )从返回 __array_struct__ 未指定。通常,它是暴露数组的对象(以便在销毁C对象时保留并销毁对它的引用)。现在明确要求以某种方式使用此字段来保存对所属对象的引用。

    注解

    在2020年8月之前,这表示:

    现在它必须是一个元组,其第一个元素是一个带有“PyArrayInterface Version#”的字符串,其第二个元素是暴露数组的对象。

    这一设计几乎在提出后立即被收回<https://mail.python.org/pipermail/numpy-discussion/2006-June/020995.html>. 尽管有14年的相反记录,但任何时候都不能认为 __array_interface__ 胶囊中含有这种元组成分。

  3. 元组从 __array_interface__['data'] 以前是十六进制字符串(现在是整数或长整数)。

  4. 没有 __array_interface__ 属性而不是中的所有键(版本除外) __array_interface__ 字典是它们自己的属性:因此,要获得Python端的信息,必须分别访问这些属性:

    • __array_data__

    • __array_shape__

    • __array_strides__

    • __array_typestr__

    • __array_descr__

    • __array_offset__

    • __array_mask__