Spec-Zone.ru › NumPy 1.18

Интерфейс массивов

Примечание

Эта страница описывает специфичный для numpy API для доступа к содержимому массива numpy из других расширений C. PEP 3118 – The Revised Buffer Protocol вводит похожий, стандартизированный API для Python 2.6 и 3.0, который любой модуль расширения может использовать. Cython’s buffer array support использует API PEP 3118; см. учебник по numpy для Cython. 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 или long). Обратите внимание, что эти целые числа могут быть больше, чем может вместить платформа “int” или “long” (целое число Python — это C long). Код, использующий этот атрибут, должен уметь обрабатывать это должным образом; либо путем повышения ошибки, когда переполнение возможно, либо с использованием Py_LONG_LONG в качестве типа C для форм.

typestr (обязательно)

Строка, определяющая базовый тип однородного массива. Базовый формат строки состоит из 3 частей: символ, описывающий порядок байтов данных (<: little-endian, >: big-endian, |: не относится), символ-код, дающий базовый тип массива, и целое число, указывающее количество байтов, используемых типом.

Основные символы типов:

t

Поле бит (следующее целое число задает количество бит в поле бит).

b

Булево (целый тип, где все значения — только True или False)

i

Целое число

u

Беззнаковое целое число

f

Число с плавающей точкой

c

Комплексное число с плавающей точкой

m

Timedelta

M

Datetime

O

Объект (то есть память содержит указатель на PyObject)

S

Строка (фиксированная длина последовательности char)

U

Unicode (фиксированная длина последовательности Py_UNICODE)

V

Другое (void * — каждый элемент — фиксированный фрагмент памяти)

descr (необязательно)

Список кортежей, предоставляющий более подробное описание структуры памяти для каждого элемента в однородном массиве. Каждый кортеж в списке имеет два или три элемента. Обычно этот атрибут используется, когда typestr — V[0-9]+, но это не обязательно. Единственное требование состоит в том, что количество байтов, представленных в ключе typestr, совпадает с общим количеством байтов, представленных здесь. Идея состоит в том, чтобы поддержать описания C-подобных структур, составляющих элементы массива. Элементы каждого кортежа в списке:

  1. Строка, предоставляющая имя, связанное с этой частью типа данных. Это также может быть кортеж из ('full name', 'basic_name'), где базовое имя — допустимое имя переменной Python, представляющее полное имя поля.
  2. Описание строки базового типа, как и в typestr, или другой список (для вложенных структурных типов)
  3. Необязательный кортеж shapes, указывающий, сколько раз эта часть структуры должна повторяться. Повторы не предполагаются, если это не указано. Очень сложные структуры можно описать с помощью этого обобщенного интерфейса. Однако обратите внимание, что каждый элемент массива все еще имеет тот же тип данных.

Значение по умолчанию: [('', typestr)]

data (необязательно)

2-кортеж, первый аргумент которого — целое число (целое число long, если необходимо), указывающее на область данных, хранящую содержимое массива. Этот указатель должен указывать на первый элемент данных (иначе любые смещения всегда игнорируются в этом случае). Второй элемент кортежа — флаг только для чтения (True означает, что область данных только для чтения).

Этот атрибут также может быть объектом, раскрывающим buffer interface, который будет использоваться для совместного использования данных. Если этот ключ отсутствует (или возвращает None), то совместное использование памяти будет выполняться через интерфейс буфера самого объекта. В этом случае ключ смещения может использоваться для указания начала буфера. Ссылка на объект, раскрывающий интерфейс массива, должна храниться новым объектом, если область памяти должна быть защищена.

Значение по умолчанию: None

strides (необязательно)

Либо None для указания C-стильного непрерывного массива, либо кортеж смещений, который предоставляет количество байтов, необходимых для перехода к следующему элементу массива в соответствующем измерении. Каждый элемент должен быть целым числом (целое число Python int или long). Как и с shape, значения могут быть больше, чем может представить C “int” или “long”; вызывающий код должен обрабатывать это должным образом, либо путем повышения ошибки, либо с использованием Py_LONG_LONG в C. По умолчанию используется None, что подразумевает непрерывный буфер памяти в стиле C. В этой модели последнее измерение массива изменяется быстрее всего. Например, кортеж смещений по умолчанию для объекта, чьи элементы массива имеют длину 8 байт, а форма — (10,20,30), будет (4800, 240, 8)

Значение по умолчанию: None (непрерывный в стиле C)

mask (необязательно)

None или объект, раскрывающий интерфейс массива. Все элементы маски массива должны интерпретироваться только как истинные или не истинные, указывая, какие элементы этого массива действительны. Форма этого объекта должна быть “broadcastable” к форме исходного массива.

Значение по умолчанию: None (все значения массива действительны)

offset (необязательно)

Смещение в области данных массива. Это может быть использовано только когда data равно None или возвращает объект buffer.

Значение по умолчанию: 0.

version (обязательно)

Целое число, показывающее версию интерфейса (т. е. 3 для этой версии). Будьте внимательны, не используйте это для аннулирования объектов, раскрывающих будущие версии интерфейса.

Доступ к C-структуре

Этот подход к интерфейсу массива позволяет быстрее получить доступ к массиву, используя только один поиск атрибута и хорошо определенную C-структуру.

__array_struct__

Тип :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 бит, показывающих, как данные должны интерпретироваться, и одного бита, показывающего, как интерфейс должен интерпретироваться. Биты данных — CONTIGUOUS (0x1), FORTRAN (0x2), ALIGNED (0x100), NOTSWAPPED (0x200) и WRITEABLE (0x400). Конечный флаг ARR_HAS_DESCR (0x800) указывает, есть ли поле arrdescr.

Новое с 16 июня 2006 г.:

В прошлом большинство реализаций использовали член “desc” самого PyCObject (не путайте это с членом “descr” структуры PyArrayInterface выше — это две разные вещи) для хранения указателя на объект, раскрывающий интерфейс. Теперь это явная часть интерфейса. Убедитесь, что вы владеете ссылкой на объект при создании PyCObject с помощью PyCObject_FromVoidPtrAndDesc.

END_OF_DOCUMENT_MARKER

Примеры описания типа

Для большей ясности полезно привести несколько примеров описания типа и соответствующих записей __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')]

Должно быть понятно, что любой структурированный тип можно описать с помощью этого интерфейса.

Отличия от интерфейса массива (версия 2)

Интерфейс версии 2 был очень похожим. Отличия были в основном эстетическими. В частности:

  1. Структура PyArrayInterface не имела члена descr в конце (и, следовательно, флага ARR_HAS_DESCR)
  2. Член desc объекта PyCObject, возвращаемого из __array_struct__, не был указан. Обычно это был объект, экспонирующий массив (чтобы можно было сохранить ссылку на него и уничтожить при уничтожении объекта C). Теперь это должен быть кортеж, первый элемент которого — строка с «PyArrayInterface Версия #», а второй — объект, экспонирующий массив.
  3. Кортеж, возвращаемый из __array_interface__[‘data’], раньше был строкой в шестнадцатеричном формате (сейчас это целое или длинное целое число).
  4. Атрибут __array_interface__ отсутствовал, вместо этого все ключи (кроме версии) в словаре __array_interface__ были своими собственными атрибутами: Таким образом, для получения информации со стороны Python нужно было отдельно получить доступ к атрибутам:

    • __array_data__
    • __array_shape__
    • __array_strides__
    • __array_typestr__
    • __array_descr__
    • __array_offset__
    • __array_mask__

© 2005–2020 NumPy Developers
Licensed under the 3-clause BSD License.
https://numpy.org/doc/1.18/reference/arrays.interface.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API