Интерфейс массива
Примечание
Эта страница описывает специфичный для 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, поскольку он имеет обратную совместимость, используя интерфейс массива, описанный здесь.
| версия: | 3 |
|---|
Интерфейс массива (иногда называемый протоколом массива) был создан в 2005 году как способ для объектов Python, подобных массивам, разумно повторно использовать буферы данных друг друга, когда это возможно. Однородный N-мерный интерфейс массива является механизмом по умолчанию для объектов, чтобы обмениваться N-мерной памятью массива и информацией. Интерфейс состоит из сторон Python и C, использующих два атрибута. Объекты, желающие считаться N-мерным массивом в коде приложения, должны поддерживать хотя бы один из этих атрибутов. Объекты, желающие поддерживать N-мерный массив в коде приложения, должны искать хотя бы один из этих атрибутов и использовать предоставленную информацию соответствующим образом.
Этот интерфейс описывает однородные массивы в том смысле, что каждый элемент массива имеет один и тот же «тип». Этот тип может быть очень простым или довольно произвольным и сложным C-подобным структурой.
Существует два способа использования интерфейса: сторона Python и сторона C. Оба являются отдельными атрибутами.
Сторона Python
Этот подход к интерфейсу состоит в том, что объект имеет атрибут __array_interface__.
-
__array_interface__ -
Словарь элементов (3 обязательных и 5 необязательных). Необязательные ключи в словаре имеют подразумеваемые значения по умолчанию, если они не предоставлены.
Ключи:
shape (обязательно)
Кортеж, элементы которого представляют размер массива в каждом измерении. Каждый элемент — целое число (целое или длинное целое число Python). Обратите внимание, что эти целые числа могут быть больше, чем может содержать платформа «int» или «long» (целое число Python — это C long). Код, использующий этот атрибут, должен обрабатывать это должным образом; либо путем выдачи ошибки, когда переполнение возможно, либо с помощьюPy_LONG_LONGв качестве типа C для форм.typestr (обязательно)
Строка, предоставляющая базовый тип однородного массива. Базовый формат строки состоит из 3 частей: символ, описывающий порядок байтов данных (
<: little-endian,>: big-endian,|: нерелевантно), символ кода, дающий базовый тип массива, и целое число, предоставляющее количество байтов, используемых типом.Основные символы типа:
tПоле бита (следующее целое число указывает количество битов в поле бита). bБулево (целый тип, где все значения — только True или False) iЦелое число uЦелое беззнаковое fЧисло с плавающей точкой cКомплексное число с плавающей точкой mTimedelta MDatetime OОбъект (т.е. память содержит указатель на PyObject)SСтрока (последовательность символов фиксированной длины) UUnicode (последовательность Py_UNICODEфиксированной длины)VДругой (void * — каждый элемент — фиксированный кусок памяти) descr (необязательно)
Список кортежей, предоставляющий более подробное описание структуры памяти для каждого элемента в однородном массиве. Каждый кортеж в списке имеет два или три элемента. Обычно этот атрибут используется, когда typestr является
V[0-9]+, но это не обязательно. Единственное требование состоит в том, что количество байтов, представленных в ключе typestr, совпадает с общим количеством байтов, представленных здесь. Идея состоит в том, чтобы поддержать описания C-подобных структур, составляющих элементы массива. Элементы каждого кортежа в списке:- Строка, предоставляющая имя, связанное с этой частью типа данных. Это также может быть кортеж
('full name', 'basic_name'), где базовое имя будет допустимым именем переменной Python, представляющим полное имя поля. - Базовая строка описания типа, как в typestr, или другой список (для вложенных типов структур)
- Необязательный кортеж размеров, указывающий, сколько раз эта часть структуры должна повторяться. Если это не указано, повторяются повторения.
Значение по умолчанию:
[('', typestr)]data (необязательно)
2-кортеж, первый элемент которого — целое число (длинное целое число, если необходимо), указывающее на область данных, хранящую содержимое массива. Этот указатель должен указывать на первый элемент данных (иначе любые смещения игнорируются в этом случае). Второй элемент кортежа — флаг только для чтения (true означает, что область данных только для чтения).
Этот атрибут также может быть объектом, который предоставляет
buffer interface, который будет использоваться для совместного использования данных. Если этот ключ отсутствует (или возвращаетNone), то совместное использование памяти будет выполнено через интерфейс буфера самого объекта. В этом случае ключ смещения может использоваться для указания начала буфера. Ссылка на объект, предоставляющий интерфейс массива, должна храниться новым объектом, если область памяти должна быть защищена.Значение по умолчанию:
Nonestrides (необязательно)
Либо
Noneдля указания непрерывного массива в стиле C, либо кортеж смещений, который содержит количество байтов, необходимых для перехода к следующему элементу массива в соответствующем измерении. Каждый элемент должен быть целым числом (целое или длинное целое число Python). Как и с формой, значения могут быть больше, чем могут быть представлены C «int» или «long»; вызывающий код должен обрабатывать это должным образом, либо путем выдачи ошибки, либо с помощьюPy_LONG_LONGв C. Значение по умолчанию —None, что подразумевает непрерывный буфер памяти в стиле C. В этой модели последнее измерение массива изменяется быстрее всего. Например, кортеж смещений по умолчанию для объекта, чьи элементы массива имеют длину 8 байт и форма (10,20,30), будет (4800, 240, 8)Значение по умолчанию:
None(непрерывный в стиле C)mask (необязательно)
Noneили объект, предоставляющий интерфейс массива. Все элементы массива маски должны интерпретироваться только как истинные или ложные, указывающие, какие элементы этого массива допустимы. Форма этого объекта должна быть“broadcastable”форме исходного массива.Значение по умолчанию:
None(все значения массива допустимы)offset (необязательно)
Целое смещение в области данных массива. Это может быть использовано только при данных
Noneили возвращении объектаbuffer.Значение по умолчанию: 0.
version (обязательно)
Целое число, показывающее версию интерфейса (например, 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 битов, показывающих, как интерпретировать данные, и одного бита, показывающего, как интерпретировать интерфейс. Бит данных — CONTIGUOUS (0x1), FORTRAN (0x2), ALIGNED (0x100), NOTSWAPPED (0x200) и WRITEABLE (0x400). Конечный флаг ARR_HAS_DESCR (0x800) указывает, присутствует ли поле arrdescr.
Новое с 16 июня 2006 г.:
В прошлом большинство реализаций использовали член «desc» в самом PyCObject (не путать с членом «descr» структуры PyArrayInterface выше — это две разные вещи), чтобы хранить указатель на объект, предоставляющий интерфейс. Теперь это явная часть интерфейса. Убедитесь, что вы владеете ссылкой на объект, когда PyCObject создается с помощью PyCObject_FromVoidPtrAndDesc.
Примеры описания типов
Для большей ясности полезно привести несколько примеров описания типа и соответствующих записей __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 был очень похожим. Различия были в основном косметическими. В частности:
- Структура PyArrayInterface не имела члена descr в конце (и, следовательно, нет флага ARR_HAS_DESCR)
- Член desc объекта PyCObject, возвращаемого из __array_struct__, не был указан. Обычно это был объект, экспонирующий массив (чтобы ссылка на него могла быть сохранена и уничтожена при уничтожении объекта C). Теперь это должен быть кортеж, первый элемент которого — строка с «PyArrayInterface Версия #», а второй — объект, экспонирующий массив.
- Кортеж, возвращаемый из __array_interface__[‘data’], раньше был шестнадцатеричной строкой (сейчас это целое или длинное целое число).
- Атрибута __array_interface__ не было, вместо этого все ключи (кроме версии) в словаре __array_interface__ были своими собственными атрибутами: Таким образом, чтобы получить информацию со стороны Python, вам нужно было отдельно получить доступ к атрибутам:
- __array_data__
- __array_shape__
- __array_strides__
- __array_typestr__
- __array_descr__
- __array_offset__
- __array_mask__
© 2008–2016 NumPy Developers
Licensed under the NumPy License.
https://docs.scipy.org/doc/numpy-1.11.0/reference/arrays.interface.html