Интерфейс массивов
Примечание
Эта страница описывает специфический для numpy API для доступа к содержимому массива numpy из других расширений C. PEP 3118 – The Revised Buffer Protocol представляет аналогичный стандартизированный API для Python 2.6 и 3.0, который любой модуль расширения может использовать. Cython’s buffer array support использует PEP 3118 API; см. учебник по 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). Код, использующий этот атрибут, должен сам обрабатывать это должным образом; либо, подняв ошибку, когда переполнение возможно, либо используяPy_LONG_LONGв качестве типа C для форм.typestr (обязательно)
Строка, предоставляющая базовый тип однородного массива. Базовый формат строки состоит из 3 частей: символ, описывающий порядок байтов данных (
<: little-endian,>: big-endian,|: не относится), символ, указывающий на базовый тип массива, и целое число, представляющее количество байтов, используемых типом.Основные символы типов:
tПоле бита (после целого числа указывается количество битов в поле бита). bБулево (целочисленный тип, где все значения только True или False) iЦелое число uБеззнаковое целое число fЧисло с плавающей точкой cКомплексное число с плавающей точкой OОбъект (то есть память содержит указатель на PyObject)SСтрока (последовательность символов фиксированной длины) UUnicode (последовательность Py_UNICODEфиксированной длины)VДругое (void * — каждый элемент — фиксированный фрагмент памяти) descr (необязательно)
Список кортежей, предоставляющих более подробное описание структуры памяти для каждого элемента в однородном массиве. Каждый кортеж в списке имеет два или три элемента. Обычно этот атрибут использовался бы, когда typestr
V[0-9]+, но это не обязательно. Единственное требование состоит в том, что количество байтов, представленных в ключе typestr, должно быть таким же, как общее количество байтов, представленных здесь. Идея заключается в поддержке описаний структур наподобие C, составляющих элементы массива. Элементами каждого кортежа в списке являются- Строка, предоставляющая имя, связанное с этой частью типа данных. Это также может быть кортеж из
('full name', 'basic_name'), где основное имя будет допустимым именем переменной Python, представляющим полное имя поля. - Либо строка описания базового типа, как в typestr, либо другой список (для вложенных структурированных типов)
- Необязательный кортеж shape, показывающий, сколько раз эта часть структуры должна повторяться. Если это не указано, повторений не предполагается. Очень сложные структуры могут быть описаны с помощью этого универсального интерфейса. Обратите внимание, что каждый элемент массива все еще имеет один и тот же тип данных.
По умолчанию:
[('', typestr)]data (необязательно)
Кортеж из 2 элементов, первый из которых — целое число (длинное целое, если необходимо), указывающее на область данных, хранящую содержимое массива. Этот указатель должен указывать на первый элемент данных (другими словами, любой смещение в данном случае игнорируется). Второй элемент кортежа — флаг только для чтения (true означает, что область данных только для чтения).
Этот атрибут также может быть объектом, который раскрывает
buffer interface, который будет использоваться для совместного использования данных. Если этот ключ отсутствует (или возвращаетNone), совместное использование памяти будет выполняться через интерфейс буфера самого объекта. В этом случае смещение может быть использовано для указания начала буфера. Ссылка на объект, раскрывающий интерфейс массива, должна быть сохранена новым объектом, если область памяти должна быть защищена.По умолчанию:
Nonestrides (необязательно)
Либо
Noneдля указания C-стильного непрерывного массива, или кортеж шагов, который предоставляет количество байтов, необходимых для перехода к следующему элементу массива в соответствующей размерности. Каждый элемент должен быть целым числом (Pythonintилиlong). Как и в случае с формой, значения могут быть больше, чем могут быть представлены C «int» или «long»; вызывающий код должен обработать это должным образом, либо подняв ошибку, либо используяPy_LONG_LONGв C. По умолчаниюNone, что подразумевает C-стильный непрерывный буфер памяти. В этой модели последняя размерность массива меняется быстрее всего. Например, кортеж шагов по умолчанию для объекта, чьи элементы массива имеют длину 8 байтов, а форма (10, 20, 30), будет (4800, 240, 8)По умолчанию:
None(C-стиль непрерывный)mask (необязательно)
Noneили объект, раскрывающий интерфейс массива. Все элементы маски массива должны интерпретироваться только как true или false, указывая, какие элементы этого массива допустимы. Форма этого объекта должна быть“broadcastable”по отношению к форме исходного массива.По умолчанию:
None(Все значения массива допустимы)offset (необязательно)
Целое смещение в области данных массива. Это можно использовать только тогда, когда данные
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.
Примеры описания типа
Для большей ясности полезно привести примеры описания типа и соответствующих записей __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 Version #”, а второй — объект, экспонирующий массив.
- Кортеж, возвращаемый из __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.10.1/reference/arrays.interface.html