Spec-Zone.ru › NumPy 1.21

Типы Python и C-структуры

В коде на C определено несколько новых типов. Большинство из них доступны из Python, но некоторые не экспонируются из-за ограниченного использования. Каждый новый тип Python связан с PyObject*, внутренняя структура которого включает указатель на «таблицу методов», определяющую поведение нового объекта в Python. Когда вы получаете объект Python в коде C, вы всегда получаете указатель на структуру PyObject. Поскольку структура PyObject очень универсальна и определяет только PyObject_HEAD, сама по себе она не очень интересна. Однако разные объекты содержат больше деталей после PyObject_HEAD (но вам нужно выполнить приведение к соответствующему типу, чтобы получить к ним доступ — или использовать функции-акцессоры или макросы).

Определенные новые типы Python

Типы Python — функциональный эквивалент классов в Python в C. Создавая новый тип Python, вы делаете доступным новый объект для Python. Объект ndarray является примером нового типа, определенного в C. Новые типы определяются в C двумя основными шагами:

  1. создание C-структуры (обычно с именем Py{Name}Object), которая совместима по бинарному представлению со структурой PyObject, но хранит дополнительную информацию, необходимую для этого конкретного объекта;
  2. заполнение таблицы PyTypeObject (на которую указывает член ob_type структуры PyObject) указателями на функции, которые реализуют желаемое поведение для типа.

Вместо специальных имен методов, определяющих поведение для классов Python, существуют «таблицы функций», которые указывают на функции, реализующие желаемые результаты. С Python 2.2 PyTypeObject стала динамической, что позволяет типам C быть «подтипами» других типов C в C и подклассами в Python. Дочерние типы наследуют атрибуты и методы от своих родительских типов.

Есть два основных новых типа: ndarray ( PyArray_Type ) и ufunc ( PyUFunc_Type ). Дополнительные типы играют вспомогательную роль: PyArrayIter_Type, PyArrayMultiIter_Type и PyArrayDescr_Type. PyArrayIter_Type — тип плоского итератора для ndarray (объект, возвращаемый при получении атрибута flat). PyArrayMultiIter_Type — тип объекта, возвращаемого при вызове broadcast (). Он обрабатывает итерацию и вещание по коллекции вложенных последовательностей. Кроме того, PyArrayDescr_Type — тип описателя типа данных, экземпляры которого описывают данные. Наконец, существует 21 новый скалярный тип массива, представляющий собой новые скаляры Python, соответствующие каждому из основных типов данных, доступных для массивов. Ещё 10 типов являются заглушками, позволяющими скалярам массива вписаться в иерархию реальных типов Python.

PyArray_Type и PyArrayObject

PyTypeObjectPyArray_Type

Тип Python ndarray — PyArray_Type. В C каждый ndarray — указатель на структуру PyArrayObject. Член ob_type этой структуры содержит указатель на тип PyArray_Type.

END_OF_DOCUMENT_MARKER
typePyArrayObject
typeNPY_AO

Структура PyArrayObject C содержит всю необходимую информацию для массива. Все экземпляры ndarray (и его подклассов) будут иметь эту структуру. Для будущей совместимости члены этой структуры обычно должны быть доступны с помощью предоставленных макросов. Если вам нужен более короткий имя, вы можете использовать NPY_AO (устаревший), который определен как эквивалентный PyArrayObject. Прямой доступ к полям структуры устарел. Используйте PyArray_*(arr) вместо этого. Начиная с NumPy 1.20, размер этой структуры не считается частью NumPy ABI (см. примечание в конце списка членов).

typedef struct PyArrayObject {
    PyObject_HEAD
    char *data;
    int nd;
    npy_intp *dimensions;
    npy_intp *strides;
    PyObject *base;
    PyArray_Descr *descr;
    int flags;
    PyObject *weakreflist;
    /* version dependend private members */
} PyArrayObject;
PyObject_HEAD

Это необходимо для всех объектов Python. Он состоит (по крайней мере) из счетчика ссылок ( ob_refcnt ) и указателя на тип объекта ( ob_type ). (Другие элементы также могут присутствовать, если Python был скомпилирован со специальными опциями. Смотрите Include/object.h в исходном коде Python для получения дополнительной информации). Член ob_type указывает на объект типа Python.

char*data

Доступно через PyArray_DATA, этот член данных — указатель на первый элемент массива. Этот указатель можно (и обычно следует) перевести в тип данных массива.

intnd

Целое число, определяющее количество измерений для этого массива. Когда nd равно 0, массив иногда называют массивом ранга 0. Такие массивы имеют неопределенные размеры и шаги и не могут быть обработаны. Макрос PyArray_NDIM, определенный в ndarraytypes.h, указывает на этот член данных. NPY_MAXDIMS — это максимальное количество измерений для любого массива.

npy_intpdimensions

Массив целых чисел, предоставляющий форму в каждом измерении, пока nd \(\geq\) 1. Целое число всегда достаточно велико, чтобы содержать указатель на платформе, поэтому размер измерения ограничен только памятью. Макрос PyArray_DIMS ассоциирован с этим членом данных.

npy_intp*strides

Массив целых чисел, предоставляющий для каждого измерения количество байтов, которые необходимо пропустить, чтобы перейти к следующему элементу в этом измерении. Ассоциировано с макросом PyArray_STRIDES.

PyObject*base

На который указывает PyArray_BASE, этот член используется для хранения указателя на другой объект Python, связанный с этим массивом. Существует два случая использования:

  • Если этот массив не владеет собственной памятью, то base указывает на объект Python, который им владеет (возможно, другой объект массива)
  • Если для этого массива установлен (устаревший) флаг NPY_ARRAY_UPDATEIFCOPY или NPY_ARRAY_WRITEBACKIFCOPY, то этот массив является рабочей копией «неправильного» массива.

При вызове PyArray_ResolveWritebackIfCopy, массив, на который указывает base, будет обновлен содержимым этого массива.

PyArray_Descr*descr

Указатель на объект описателя типа данных (см. ниже). Объект описателя типа данных — это экземпляр нового встроенного типа, который позволяет описывать память в общем виде. Существует структура описателя для каждого поддерживаемого типа данных. Эта структура описателя содержит полезную информацию о типе, а также указатель на таблицу указателей на функции для реализации конкретных функций. Как следует из названия, она связана с макросом PyArray_DESCR.

intflags

На который указывает макрос PyArray_FLAGS, этот член данных представляет флаги, указывающие, как интерпретировать память, на которую указывает data. Возможные флаги: NPY_ARRAY_C_CONTIGUOUS, NPY_ARRAY_F_CONTIGUOUS, NPY_ARRAY_OWNDATA, NPY_ARRAY_ALIGNED, NPY_ARRAY_WRITEABLE, NPY_ARRAY_WRITEBACKIFCOPY и NPY_ARRAY_UPDATEIFCOPY.

PyObject*weakreflist

Этот член позволяет объектам массива иметь слабые ссылки (с использованием модуля weakref).

Примечание

Дополнительные члены считаются закрытыми и зависят от версии. Если размер структуры важен для вашего кода, необходимо проявлять особую осторожность. Возможным случаем использования, когда это актуально, является наследование в C. Если ваш код полагается на sizeof(PyArrayObject) как на постоянную величину, вам необходимо добавить следующую проверку во время импорта:

if (sizeof(PyArrayObject) < PyArray_Type.tp_basicsize) {
    PyErr_SetString(PyExc_ImportError,
       "Binary incompatibility with NumPy, must recompile/update X.");
    return NULL;
}

Чтобы ваш код не нужно было компилировать для определенной версии NumPy, вы можете добавить константу, оставив место для изменений в NumPy. Решение, гарантирующее совместимость с любой будущей версией NumPy, требует использования вычисления смещения и размера выделения во время выполнения.

PyArrayDescr_Type и PyArray_Descr

PyTypeObjectPyArrayDescr_Type

Тип PyArrayDescr_Type — это встроенный тип объектов описателей типа данных, используемых для описания того, как следует интерпретировать байты, составляющие массив. Существует 21 статически определенный объект PyArray_Descr для встроенных типов данных. Хотя они участвуют в подсчете ссылок, их счетчик ссылок никогда не должен достигать нуля. Также поддерживается динамическая таблица объектов пользовательских PyArray_Descr. После «регистрации» объекта описателя типа данных его также не следует удалять. Функция PyArray_DescrFromType (…) может использоваться для извлечения объекта PyArray_Descr из перечислимого номера типа (встроенного или пользовательского).

typePyArray_Descr

Структура PyArray_Descr лежит в основе PyArrayDescr_Type. Хотя она описана здесь для полноты, её следует считать внутренней для NumPy и манипулировать с помощью функций или макросов PyArrayDescr_* или PyDataType*. Размер этой структуры может меняться в разных версиях NumPy. Чтобы обеспечить совместимость:

  • Никогда не объявляйте не-указатель экземпляра структуры.
  • Никогда не выполняйте арифметику указателей.
  • Никогда не используйте sizof(PyArray_Descr)

Она имеет следующую структуру:

typedef struct {
    PyObject_HEAD
    PyTypeObject *typeobj;
    char kind;
    char type;
    char byteorder;
    char flags;
    int type_num;
    int elsize;
    int alignment;
    PyArray_ArrayDescr *subarray;
    PyObject *fields;
    PyObject *names;
    PyArray_ArrFuncs *f;
    PyObject *metadata;
    NpyAuxData *c_metadata;
    npy_hash_t hash;
} PyArray_Descr;
PyTypeObject*typeobj

Указатель на тип объекта, соответствующий Python-типу элементов этого массива. Для встроенных типов это указывает на соответствующий скаляр массива. Для типов, определённых пользователем, это должно указывать на объект пользовательского типа. Этот тип объекта может унаследовать или нет от скаляров массива. Если он не наследует от скаляров массива, то флаги NPY_USE_GETITEM и NPY_USE_SETITEM должны быть установлены в члене flags.

charkind

Символьный код, указывающий тип массива (используя обозначение типов в строке интерфейса массива). ‘b’ представляет булевы значения, ‘i’ — целые со знаком, ‘u’ — целые без знака, ‘f’ — числа с плавающей точкой, ‘c’ — комплексные числа с плавающей точкой, ‘S’ — 8-битовые нуль-терминированные байты, ‘U’ — 32-битовые/символьные строки Unicode, и ‘V’ — произвольные.

chartype

Традиционный символьный код, указывающий тип данных.

charbyteorder

Символ, указывающий порядок байтов: ‘>’ (большая эндианность), ‘<’ (малая эндианность), ‘=’ (родной), ‘|’ (не имеет значения, игнорировать). Все встроенные типы данных имеют порядок байтов ‘=’.

charflags

Флаги типа данных, определяющие, обладает ли тип данных поведением, подобным массиву объектов. Каждый бит в этом члене является флагом, имеющим следующие названия:

NPY_ITEM_REFCOUNT

Указывает, что элементы этого типа данных должны быть подсчитаны со ссылкой (с использованием Py_INCREF и Py_DECREF).

NPY_ITEM_HASOBJECT

То же, что и NPY_ITEM_REFCOUNT.

NPY_LIST_PICKLE

Указывает, что массивы этого типа данных должны быть преобразованы в список перед сериализацией.

NPY_ITEM_IS_POINTER

Указывает, что элемент является указателем на другие данные.

NPY_NEEDS_INIT

Указывает, что память для этого типа данных должна быть инициализирована (обнулена) при создании.

NPY_NEEDS_PYAPI

Указывает, что этому типу данных нужен Python C-API при доступе (поэтому не отпускайте GIL, если требуется доступ к массиву).

NPY_USE_GETITEM

При доступе к массиву используйте указатель функции f->getitem вместо стандартного преобразования в скаляр массива. Нужно использовать, если вы не определяете скаляр массива для работы с типом данных.

NPY_USE_SETITEM

При создании 0-мерного массива из скаляра массива используйте f->setitem вместо стандартной копии из скаляра массива. Нужно использовать, если вы не определяете скаляр массива для работы с типом данных.

NPY_FROM_FIELDS

Биты, унаследованные от родительского типа данных, если эти биты установлены в любом поле типа данных. В настоящее время ( NPY_NEEDS_INIT | NPY_LIST_PICKLE | NPY_ITEM_REFCOUNT | NPY_NEEDS_PYAPI ).

NPY_OBJECT_DTYPE_FLAGS

Биты, установленные для типа данных объекта: ( NPY_LIST_PICKLE | NPY_USE_GETITEM | NPY_ITEM_IS_POINTER | NPY_ITEM_REFCOUNT | NPY_NEEDS_INIT | NPY_NEEDS_PYAPI).

intPyDataType_FLAGCHK(PyArray_Descr*dtype, intflags)

Возвращает истину, если все заданные флаги установлены для объекта типа данных.

intPyDataType_REFCHK(PyArray_Descr*dtype)

Эквивалентно PyDataType_FLAGCHK (dtype, NPY_ITEM_REFCOUNT).

inttype_num

Число, которое однозначно идентифицирует тип данных. Для новых типов данных это число назначается при регистрации типа данных.

intelsize

Для типов данных, которые всегда имеют одинаковый размер (например, long), здесь хранится размер типа данных. Для гибких типов данных, где разные массивы могут иметь различный размер элемента, это значение должно быть 0.

intalignment

Число, предоставляющее информацию об выравнивании для этого типа данных. В частности, оно показывает, насколько далеко от начала двухелементной структуры (первым элементом которой является char ), компилятор помещает элемент этого типа: offsetof(struct {char c; type v;}, v)

PyArray_ArrayDescr*subarray

Если это не NULL, то этот описатель типа данных является C-стильным контигуозным массивом другого описателя типа данных. Другими словами, каждый элемент, описываемый этим описателем, фактически является массивом некоторого другого базового описателя. Это наиболее полезно в качестве описателя типа данных для поля в другом описателе типа данных. Член fields должен быть NULL, если это не NULL (член fields базового описателя может быть не NULL, однако).

typePyArray_ArrayDescr
typedef struct {
    PyArray_Descr *base;
    PyObject *shape;
} PyArray_ArrayDescr;
PyArray_Descr*base

Объект описателя типа базового типа.

PyObject*shape

Форма (всегда C-стильная контигуозная) подмассива в виде кортежа Python.

PyObject*fields

Если это не NULL, то этот описатель типа данных имеет поля, описанные словарем Python, ключами которого являются имена (а также заголовки, если заданы), а значениями — кортежи, описывающие поля. Запомните, что описатель типа данных всегда описывает фиксированный набор байтов. Поле — это именованная подобласть этого общего, фиксированного по длине набора. Поле описывается кортежем, состоящим из другого описателя типа данных и смещения байтов. По желанию кортеж может содержать заголовок, который обычно является строкой Python. Эти кортежи помещаются в этот словарь с ключом по имени (а также по заголовку, если он задан).

PyObject*names

Упорядоченный кортеж имён полей. Он равен NULL, если поля не определены.

PyArray_ArrFuncs*f

Указатель на структуру, содержащую функции, которые тип должен реализовать для внутренних функций. Эти функции не являются теми же, что универсальные функции (ufuncs), описанные позже. Их сигнатуры могут варьироваться произвольным образом.

PyObject*metadata

Метаданные об этом dtype.

NpyAuxData*c_metadata

Метаданные, специфичные для реализации dtype на C. Добавлено для NumPy 1.7.0.

typenpy_hash_t
npy_hash_t*hash

В настоящее время не используется. Зарезервировано для будущего использования в кэшировании хеш-значений.

typePyArray_ArrFuncs

Функции, реализующие внутренние возможности. Не все указатели на эти функции должны быть определены для данного типа. Требуемые члены — nonzero, copyswap, copyswapn, setitem, getitem, и cast. Предполагается, что они не NULL и NULL записи приведут к сбою программы. Другие функции могут быть NULL, что просто означает уменьшенную функциональность для этого типа данных. (Кроме того, функция nonzero будет заполнена по умолчанию, если она NULL при регистрации пользовательского типа данных).

typedef struct {
    PyArray_VectorUnaryFunc *cast[NPY_NTYPES];
    PyArray_GetItemFunc *getitem;
    PyArray_SetItemFunc *setitem;
    PyArray_CopySwapNFunc *copyswapn;
    PyArray_CopySwapFunc *copyswap;
    PyArray_CompareFunc *compare;
    PyArray_ArgFunc *argmax;
    PyArray_DotFunc *dotfunc;
    PyArray_ScanFunc *scanfunc;
    PyArray_FromStrFunc *fromstr;
    PyArray_NonzeroFunc *nonzero;
    PyArray_FillFunc *fill;
    PyArray_FillWithScalarFunc *fillwithscalar;
    PyArray_SortFunc *sort[NPY_NSORTS];
    PyArray_ArgSortFunc *argsort[NPY_NSORTS];
    PyObject *castdict;
    PyArray_ScalarKindFunc *scalarkind;
    int **cancastscalarkindto;
    int *cancastto;
    PyArray_FastClipFunc *fastclip;  /* deprecated */
    PyArray_FastPutmaskFunc *fastputmask;  /* deprecated */
    PyArray_FastTakeFunc *fasttake;  /* deprecated */
    PyArray_ArgFunc *argmin;
} PyArray_ArrFuncs;

В описании указателей функций используется понятие «вежливого сегмента». Вежливый сегмент — это сегмент, выровненный и в родном порядке байтов для типа данных. Функции nonzero, copyswap, copyswapn, getitem, и setitem могут (и должны) обрабатывать массивы с неправильным поведением. Другие функции требуют вежливых сегментов памяти.

voidcast(void*from, void*to, npy_intpn, void*fromarr, void*toarr)

Массив указателей на функции для преобразования из текущего типа во все другие встроенные типы. Каждая функция преобразует непрерывный, выровненный и не инвертированный буфер, указанный по адресу from, в непрерывный, выровненный и не инвертированный буфер, указанный по адресу to. Количество элементов для преобразования задано n, а аргументы fromarr и toarr интерпретируются как PyArrayObjects для гибких массивов для получения информации о размере элемента.

PyObject*getitem(void*data, void*arr)

Указатель на функцию, которая возвращает стандартный объект Python из одного элемента объекта массива arr, на который указывает data. Эта функция должна уметь правильно обрабатывать «неправильно ведущиеся» (невыровненные и/или инвертированные) массивы.

intsetitem(PyObject*item, void*data, void*arr)

Указатель на функцию, которая помещает объект Python item в массив arr в позиции, на которую указывает data. Эта функция обрабатывает «неправильно ведущиеся» массивы. При успешном выполнении возвращается ноль, в противном случае — минус один (и возникает ошибка Python).

voidcopyswapn(void*dest, npy_intpdstride, void*src, npy_intpsstride, npy_intpn, intswap, void*arr)
voidcopyswap(void*dest, void*src, intswap, void*arr)

Эти члены — указатели на функции для копирования данных из src в dest и инвертирования байтов, если указано. Значение arr используется только для гибких ( NPY_STRING, NPY_UNICODE и NPY_VOID ) массивов (и получено из arr->descr->elsize ). Вторая функция копирует одно значение, а первая циклится по n значениям с заданными шагами. Эти функции могут обрабатывать данные src с неправильным поведением. Если src равно NULL, то копирование не выполняется. Если swap равно 0, то инвертирование байтов не происходит. Предполагается, что dest и src не перекрываются. Если они перекрываются, то сначала используйте memmove (…), а затем copyswap(n) с src равным NULL.

intcompare(constvoid*d1, constvoid*d2, void*arr)

Указатель на функцию, которая сравнивает два элемента массива, arr, на которые указывают d1 и d2. Эта функция требует вежливых (выровненных и не инвертированных) массивов. Возвращаемое значение равно 1, если * d1 > * d2, 0, если * d1 == * d2, и -1, если * d1 < * d2. Объект массива arr используется для получения информации о размере элемента и полях для гибких массивов.

intargmax(void*data, npy_intpn, npy_intp*max_ind, void*arr)

Указатель на функцию, которая возвращает индекс максимального из n элементов в arr, начиная с элемента, на который указывает data. Эта функция требует, чтобы сегмент памяти был непрерывным и вежливым. Возвращаемое значение всегда равно 0. Индекс максимального элемента возвращается в max_ind.

voiddotfunc(void*ip1, npy_intpis1, void*ip2, npy_intpis2, void*op, npy_intpn, void*arr)

Указатель на функцию, которая умножает две n-длинные последовательности, складывает их и помещает результат в элемент, на который указывает op в arr. Начало двух последовательностей указано по адресам ip1 и ip2. Для перехода к следующему элементу в каждой последовательности требуется переход на is1 и is2 байт соответственно. Эта функция требует вежливой (но не обязательно непрерывной) памяти.

intscanfunc(FILE*fd, void*ip, void*arr)

Указатель на функцию, которая считывает (в стиле scanf) один элемент соответствующего типа из дескриптора файла fd в память массива, на которую указывает ip. Массив предполагается вежливым. Последний аргумент arr — массив, в который производится считывание. Возвращает количество успешно присвоенных аргументов (может быть нулевым в случае неудачного соответствия до назначения первого аргумента) или EOF, если ошибка ввода-вывода возникает до назначения первого аргумента. Эта функция должна вызываться без блокировки Python GIL и должна захватывать её для сообщения об ошибках.

intfromstr(char*str, void*ip, char**endptr, void*arr)

Указатель на функцию, которая преобразует строку, на которую указывает str, в один элемент соответствующего типа и помещает его в место памяти, на которое указывает ip. После завершения преобразования, *endptr указывает на оставшуюся часть строки. Последний аргумент arr — это массив, на который указывает ip (необходим для типов данных переменной длины). Возвращает 0 при успехе или -1 при ошибке. Требуется вежливый массив. Эта функция должна вызываться без блокировки Python GIL, и должна захватить её для сообщения об ошибке.

npy_boolnonzero(void*data, void*arr)

Указатель на функцию, которая возвращает TRUE, если элемент arr, на который указывает data, не равен нулю. Эта функция может работать с некорректными массивами.

voidfill(void*data, npy_intplength, void*arr)

Указатель на функцию, заполняющую непрерывный массив заданной длины данными. Первые два элемента массива должны быть уже заполнены. Из этих двух значений будет вычислена разность, и значения с элемента 3 до конца будут вычислены путём многократного добавления этой вычисленной разности. Буфер данных должен быть корректным.

voidfillwithscalar(void*buffer, npy_intplength, void*value, void*arr)

Указатель на функцию, заполняющую непрерывный buffer заданной length одним скалярным значением value, адрес которого указан. Последний аргумент — массив, необходимый для получения размера элемента для массивов переменной длины.

intsort(void*start, npy_intplength, void*arr)

Массив указателей на функции для определённого алгоритма сортировки. Конкретный алгоритм сортировки определяется ключом (на данный момент NPY_QUICKSORT, NPY_HEAPSORT и NPY_MERGESORT определены). Эти сортировки выполняются на месте, предполагая непрерывные и выровненные данные.

intargsort(void*start, npy_intp*result, npy_intplength, void*arr)

Массив указателей на функции сортировки для этого типа данных. Доступны те же алгоритмы сортировки, что и для sort. Индексы, дающие сортировку, возвращаются в result (который должен быть инициализирован индексами от 0 до length-1 включительно).

PyObject*castdict

Либо NULL, либо словарь, содержащий функции низкоуровневого преобразования для типов данных, определённых пользователем. Каждая функция обернута в PyCapsule* и индексируется по номеру типа данных.

NPY_SCALARKINDscalarkind(PyArrayObject*arr)

Функция для определения того, как скаляры этого типа должны интерпретироваться. Аргумент — NULL или 0-мерный массив, содержащий данные (если это необходимо для определения типа скаляра). Значение возврата должно быть типа NPY_SCALARKIND.

int**cancastscalarkindto

Либо NULL или массив указателей NPY_NSCALARKINDS. Эти указатели должны быть либо NULL или указателем на массив целых чисел (завершённый NPY_NOTYPE), указывающий типы данных, к которым скаляр этого типа указанного вида может быть безопасно преобразован (обычно это означает без потери точности).

int*cancastto

Либо NULL или массив целых чисел (завершённый NPY_NOTYPE ), указывающий типы данных, к которым этот тип данных может быть безопасно преобразован (обычно это означает без потери точности).

voidfastclip(void*in, npy_intpn_in, void*min, void*max, void*out)

Устарело начиная с версии 1.17: Использование этой функции выдаст предупреждение об устаревании, когда np.clip. Вместо этой функции тип данных должен использовать PyUFunc_RegisterLoopForDescr для подключения пользовательского цикла к np.core.umath.clip, np.minimum, и np.maximum.

Устарело начиная с версии 1.19: Установка этой функции устарела и всегда должна быть NULL, если установлена, она будет проигнорирована.

Функция, которая считывает n_in элементов из in, и записывает в out прочитанное значение, если оно находится в пределах, указанных min и max, или соответствующий предел, если значение вне диапазона. Участки памяти должны быть непрерывными и корректными, и либо min или max может быть NULL, но не оба.

voidfastputmask(void*in, void*mask, npy_intpn_in, void*values, npy_intpnv)

Устарело начиная с версии 1.19: Установка этой функции устарела и всегда должна быть NULL, если установлена, она будет проигнорирована.

Функция, которая принимает указатель in на массив из n_in элементов, указатель mask на массив n_in булевых значений и указатель vals на массив из nv элементов. Элементы из vals копируются в in там, где значение в mask не равно нулю, с тилированием vals по мере необходимости, если nv < n_in. Все массивы должны быть непрерывными и ведомыми.

voidfasttake(void*dest, void*src, npy_intp*indarray, npy_intpnindarray, npy_intpn_outer, npy_intpm_middle, npy_intpnelem, NPY_CLIPMODEclipmode)

Устарело начиная с версии 1.19: Установка этой функции устарела и всегда должна быть NULL, если установлена, она будет проигнорирована.

Функция, которая принимает указатель src на непрерывный, ведомый сегмент, интерпретируемый как 3-мерный массив формы (n_outer, nindarray, nelem), указатель indarray на непрерывный, ведомый сегмент m_middle целочисленных индексов и указатель dest на непрерывный, ведомый сегмент, интерпретируемый как 3-мерный массив формы (n_outer, m_middle, nelem). Индексы в indarray используются для индексирования src по второму измерению и копирования соответствующих фрагментов nelem элементов в dest. clipmode (которое может принимать значения NPY_RAISE, NPY_WRAP или NPY_CLIP) определяет, как будут обрабатываться индексы, меньшие 0 или большие nindarray.

intargmin(void*data, npy_intpn, npy_intp*min_ind, void*arr)

Указатель на функцию, которая извлекает индекс наименьшего из n элементов в arr, начиная с элемента, на который указывает data. Эта функция требует, чтобы сегмент памяти был непрерывным и ведомым. Возвращаемое значение всегда равно 0. Индекс наименьшего элемента возвращается в min_ind.

Тип PyArray_Type реализует многие функции Python objects, включая интерфейсы tp_as_number, tp_as_sequence, tp_as_mapping и tp_as_buffer. Также используется rich comparison вместе с поиском атрибутов нового стиля для членов (tp_members) и свойств (tp_getset). Тип PyArray_Type также может быть подтипизирован.

Подсказка

Методы tp_as_number используют общий подход для вызова любой функции, которая была зарегистрирована для обработки операции. При импорте _multiarray_umath module, он устанавливает числовые операции для всех массивов соответствующим функциям ufuncs. Этот выбор может быть изменён с помощью PyUFunc_ReplaceLoopBySignature. Методы tp_str и tp_repr также могут быть изменены с помощью PyArray_SetStringFunction.

PyUFunc_Type и PyUFuncObject

PyTypeObjectPyUFunc_Type

Объект ufunc реализуется путём создания PyUFunc_Type. Это очень простой тип, который реализует только базовое поведение getattribute, поведение печати и имеет поведение вызова, которое позволяет этим объектам действовать как функции. Основная идея ufunc заключается в хранении ссылки на быстрые 1-мерные (векторные) циклы для каждого типа данных, который поддерживает операцию. Эти одномерные циклы все имеют одинаковую сигнатуру и являются ключом к созданию новой функции ufunc. Они вызываются общим кодом циклов по мере необходимости для реализации N-мерной функции. Также определены некоторые общие 1-мерные циклы для плавающих и комплексных плавающих массивов, которые позволяют определить функцию ufunc с использованием одной скалярной функции (например, atanh).

typePyUFuncObject

Ядро ufunc — это PyUFuncObject, содержащее всю необходимую информацию для вызова подлежащих C-код циклов, выполняющих фактическую работу. Хотя оно описано здесь для полноты, его следует считать внутренним для NumPy и манипулировать им с помощью PyUFunc_* функций. Размер этой структуры может изменяться в разных версиях NumPy. Чтобы обеспечить совместимость:

  • Никогда не объявляйте не-указатель экземпляра структуры.
  • Никогда не выполняйте арифметику указателей.
  • Никогда не используйте sizeof(PyUFuncObject)

Она имеет следующую структуру:

typedef struct {
    PyObject_HEAD
    int nin;
    int nout;
    int nargs;
    int identity;
    PyUFuncGenericFunction *functions;
    void **data;
    int ntypes;
    int reserved1;
    const char *name;
    char *types;
    const char *doc;
    void *ptr;
    PyObject *obj;
    PyObject *userloops;
    int core_enabled;
    int core_num_dim_ix;
    int *core_num_dims;
    int *core_dim_ixs;
    int *core_offsets;
    char *core_signature;
    PyUFunc_TypeResolutionFunc *type_resolver;
    PyUFunc_LegacyInnerLoopSelectionFunc *legacy_inner_loop_selector;
    PyUFunc_MaskedInnerLoopSelectionFunc *masked_inner_loop_selector;
    npy_uint32 *op_flags;
    npy_uint32 *iter_flags;
    /* new in API version 0x0000000D */
    npy_intp *core_dim_sizes;
    npy_uint32 *core_dim_flags;
    PyObject *identity_value;
} PyUFuncObject;
intnin

Количество входных аргументов.

intnout

Количество выходных аргументов.

intnargs

Общее количество аргументов (nin + nout). Оно должно быть меньше NPY_MAXARGS.

intidentity

Либо PyUFunc_One, PyUFunc_Zero, PyUFunc_MinusOne, PyUFunc_None, PyUFunc_ReorderableNone, или PyUFunc_IdentityValue для указания тождества для данной операции. Оно используется только для вызова типа reduce для пустого массива.

voidfunctions(char**args, npy_intp*dims, npy_intp*steps, void*extradata)

Массив указателей на функции — по одному для каждого типа данных, поддерживаемого ufunc. Это векторный цикл, который вызывается для реализации подлежащей функции dims [0] раз. Первый аргумент, args, — это массив из nargs указателей на данные в памяти. Указатели на данные для входных аргументов идут первыми, а затем указатели на данные для выходных аргументов. Количество байтов, которое необходимо пропустить, чтобы перейти к следующему элементу в последовательности, задается соответствующей записью в массиве steps. Последний аргумент позволяет циклу получать дополнительную информацию. Это обычно используется для того, чтобы один универсальный векторный цикл мог использоваться для нескольких функций. В этом случае фактическая скалярная функция, которую нужно вызвать, передаётся в качестве extradata. Размер этого массива указателей на функции равен ntypes.

void**data

Дополнительные данные, передаваемые в циклы 1-мерных векторов или NULL если дополнительные данные не нужны. Этот массив C должен иметь тот же размер (т.е. ntypes), что и массив функций. NULL используется, если дополнительные данные не нужны. Несколько вызовов C-API для UFuncs — это просто циклы 1-мерных векторов, которые используют эти дополнительные данные для получения указателя на фактическую вызываемую функцию.

intntypes

Количество поддерживаемых типов данных для ufunc. Это число определяет, сколько различных 1-мерных циклов (встроенных типов данных) доступно.

intreserved1

Не используется.

char*name

Строковое имя для ufunc. Используется динамически для построения атрибута __doc__ ufunc.

char*types

Массив \(nargs \times ntypes\) 8-битных номеров типов, содержащих сигнатуру типа функции для каждого из поддерживаемых (встроенных) типов данных. Для каждой из ntypes функций соответствующий набор номеров типов в этом массиве показывает, как аргумент args должен интерпретироваться в цикле 1-мерного вектора. Эти номера типов не обязательно должны быть одного типа, и поддерживаются ufunc смешанных типов.

char*doc

Документация для ufunc. Не должна содержать сигнатуру функции, так как она генерируется динамически при получении __doc__.

void*ptr

Любая динамически выделенная память. В настоящее время используется для динамически созданных ufunc из python-функций для хранения места для членов types, data и name.

PyObject*obj

Для ufunc, динамически созданных из python-функций, этот член содержит ссылку на подлежащую Python-функцию.

PyObject*userloops

Словарь пользовательских циклов 1-мерных векторов (хранящихся как указатели CObject) для пользовательских типов. Пользователь может зарегистрировать цикл для любого пользовательского типа. Он извлекается по номеру типа. Номера типов, определённые пользователем, всегда больше NPY_USERDEF.

intcore_enabled

0 для скалярных ufunc; 1 для обобщённых ufunc

intcore_num_dim_ix

Количество различных имён измерений ядра в сигнатуре

int*core_num_dims

Количество измерений ядра каждого аргумента

int*core_dim_ixs

Индексы измерений в уплощённом виде; индексы аргумента k хранятся в core_dim_ixs[core_offsets[k] : core_offsets[k] + core_numdims[k]]

int*core_offsets

Позиция первого измерения ядра каждого аргумента в core_dim_ixs, эквивалентно cumsum(core_num_dims)

char*core_signature

Строка ядровой сигнатуры

PyUFunc_TypeResolutionFunc*type_resolver

Функция, которая разрешает типы и заполняет массив dtypes для входных и выходных данных

PyUFunc_LegacyInnerLoopSelectionFunc*legacy_inner_loop_selector

Функция, возвращающая внутренний цикл. legacy в имени возникает потому, что для NumPy 1.6 планировалась лучшая версия. Эта версия ещё не появилась.

void*reserved2

Для возможного будущего селектора циклов с другой сигнатурой.

PyUFunc_MaskedInnerLoopSelectionFunc*masked_inner_loop_selector

Функция, возвращающая внутренний цикл с маской для ufunc

END_OF_DOCUMENT_MARKER
npy_uint32op_flags

Переопределите значения флагов операндов по умолчанию для каждого операнда ufunc.

npy_uint32iter_flags

Переопределите значения флагов nditer по умолчанию для ufunc.

Добавлен в версию API 0x0000000D

npy_intp*core_dim_sizes

Для каждого уникального ядра измерения, возможный размер замороженный, если UFUNC_CORE_DIM_SIZE_INFERRED равно 0

npy_uint32*core_dim_flags

Для каждого уникального ядра измерения, набор UFUNC_CORE_DIM* флагов

UFUNC_CORE_DIM_CAN_IGNORE

если имя измерения заканчивается на ?

UFUNC_CORE_DIM_SIZE_INFERRED

если размер измерения будет определён из операндов, а не из замороженной подписи

PyObject*identity_value

Идентичность для сокращения, когда PyUFuncObject.identity равна PyUFunc_IdentityValue.

Тип PyArrayIter_Type и PyArrayIterObject

PyTypeObjectPyArrayIter_Type

Это объект-итератор, который упрощает итерацию по N-мерному массиву. Он является объектом, возвращаемым атрибутом flat ndarray. Он также широко используется во внутренних реализациях для итерации по N-мерному массиву. Интерфейс tp_as_mapping реализован таким образом, что к объекту-итератору можно обращаться по индексу (используя 1-мерную индексацию), а несколько методов реализованы через таблицу tp_methods. Этот объект реализует метод next и может быть использован везде, где в Python используется итератор.

typePyArrayIterObject

C-структура, соответствующая объекту PyArrayIter_Type, — это PyArrayIterObject. PyArrayIterObject используется для отслеживания указателя в N-мерном массиве. Он содержит связанную информацию, используемую для быстрого перемещения по массиву. Указатель может быть скорректирован тремя основными способами: 1) перейти к следующей позиции в массиве в стиле C-contiguous, 2) перейти к произвольной N-мерной координате в массиве и 3) перейти к произвольному одномерному индексу в массиве. Члены структуры PyArrayIterObject используются в этих расчётах. Объекты-итераторы хранят свои собственные сведения о размерности и шагах массива. Это можно изменять по мере необходимости для «векторного вычисления» или для итерации только по определённым измерениям.

typedef struct {
    PyObject_HEAD
    int   nd_m1;
    npy_intp  index;
    npy_intp  size;
    npy_intp  coordinates[NPY_MAXDIMS];
    npy_intp  dims_m1[NPY_MAXDIMS];
    npy_intp  strides[NPY_MAXDIMS];
    npy_intp  backstrides[NPY_MAXDIMS];
    npy_intp  factors[NPY_MAXDIMS];
    PyArrayObject *ao;
    char  *dataptr;
    npy_bool  contiguous;
} PyArrayIterObject;
intnd_m1

\(N-1\), где \(N\) — число измерений в базовом массиве.

npy_intpindex

Текущий 1-мерный индекс в массиве.

npy_intpsize

Общий размер базового массива.

npy_intp*coordinates

N-мерный индекс в массиве.

npy_intp*dims_m1

Размер массива минус 1 в каждом измерении.

npy_intp*strides

Шаги массива. Сколько байтов необходимо перескочить, чтобы перейти к следующему элементу в каждом измерении.

npy_intp*backstrides

Сколько байтов необходимо перескочить, чтобы вернуться к началу измерения от конца. Обратите внимание, что backstrides[k] == strides[k] * dims_m1[k], но оно хранится здесь для оптимизации.

npy_intp*factors

Этот массив используется для вычисления N-мерного индекса из 1-мерного индекса. Он содержит необходимые произведения измерений.

PyArrayObject*ao

Указатель на базовый ndarray, который этот итератор создан для представления.

char*dataptr

Этот член указывает на элемент в ndarray, указанный индексом.

npy_boolcontiguous

Этот флаг имеет значение true, если базовый массив является NPY_ARRAY_C_CONTIGUOUS. Он используется для упрощения вычислений, когда это возможно.

Более подробное описание использования итератора массива на уровне C приведено в последующих разделах. Как правило, вам не нужно заботиться о внутренней структуре объекта-итератора и взаимодействовать с ним только с помощью макросов PyArray_ITER_NEXT (it), PyArray_ITER_GOTO (it, dest) или PyArray_ITER_GOTO1D (it, index). Все эти макросы требуют аргумент it, который должен быть PyArrayIterObject*.

PyArrayMultiIter_Type и PyArrayMultiIterObject

PyTypeObjectPyArrayMultiIter_Type

Этот тип предоставляет итератор, который обобщает концепцию вещания. Он позволяет \(N\) массивам быть объединёнными для вещания, так что цикл будет проходить по объединённому массиву в стиле C-contiguous. Соответствующая структура C — PyArrayMultiIterObject, расположение памяти которой должно начинаться с любого объекта, obj, переданного в функцию PyArray_Broadcast (obj). Вещание выполняется путём корректировки итераторов массивов, так что каждый итератор представляет собой объединённую форму и размер, но его шаги корректируются, чтобы на каждой итерации использовался правильный элемент массива.

typePyArrayMultiIterObject
typedef struct {
    PyObject_HEAD
    int numiter;
    npy_intp size;
    npy_intp index;
    int nd;
    npy_intp dimensions[NPY_MAXDIMS];
    PyArrayIterObject *iters[NPY_MAXDIMS];
} PyArrayMultiIterObject;
intnumiter

Количество массивов, которые необходимо объединить для вещания в одну форму.

npy_intpsize

Общий размер после вещания.

npy_intpindex

Текущий (1-мерный) индекс в объединённом результате.

intnd

Количество измерений в объединённом результате.

npy_intp*dimensions

Форма объединённого результата (используются только nd слоты).

PyArrayIterObject**iters

Массив объектов итераторов, содержащий итераторы для массивов, которые необходимо объединить. После возврата итераторы корректируются для вещания.

PyArrayNeighborhoodIter_Type и PyArrayNeighborhoodIterObject

PyTypeObjectPyArrayNeighborhoodIter_Type

Это объект итератора, который упрощает циклирование по окрестности N-мерного массива.

typePyArrayNeighborhoodIterObject

Структура C, соответствующая объекту PyArrayNeighborhoodIter_Type, — это PyArrayNeighborhoodIterObject.

typedef struct {
    PyObject_HEAD
    int nd_m1;
    npy_intp index, size;
    npy_intp coordinates[NPY_MAXDIMS]
    npy_intp dims_m1[NPY_MAXDIMS];
    npy_intp strides[NPY_MAXDIMS];
    npy_intp backstrides[NPY_MAXDIMS];
    npy_intp factors[NPY_MAXDIMS];
    PyArrayObject *ao;
    char *dataptr;
    npy_bool contiguous;
    npy_intp bounds[NPY_MAXDIMS][2];
    npy_intp limits[NPY_MAXDIMS][2];
    npy_intp limits_sizes[NPY_MAXDIMS];
    npy_iter_get_dataptr_t translate;
    npy_intp nd;
    npy_intp dimensions[NPY_MAXDIMS];
    PyArrayIterObject* _internal_iter;
    char* constant;
    int mode;
} PyArrayNeighborhoodIterObject;

PyArrayFlags_Type и PyArrayFlagsObject

PyTypeObjectPyArrayFlags_Type

При получении атрибута флагов из Python, создаётся специальный встроенный объект этого типа. Этот специальный тип упрощает работу с разными флагами, предоставляя доступ к ним как к атрибутам или как к элементам словаря с именами флагов в качестве ключей.

typePyArrayFlagsObject
typedef struct PyArrayFlagsObject {
        PyObject_HEAD
        PyObject *arr;
        int flags;
} PyArrayFlagsObject;

Типы скалярных массивов

Для каждого встроенного типа данных, который может быть в массиве, существует тип Python. Большинство из них — это простые оболочки вокруг соответствующего типа данных в C. Имена типов в C — Py{TYPE}ArrType_Type , где {TYPE} может быть

Bool, Byte, Short, Int, Long, LongLong, UByte, UShort, UInt, ULong, ULongLong, Half, Float, Double, LongDouble, CFloat, CDouble, CLongDouble, String, Unicode, Void и Object.

Эти имена типов являются частью C-API и, следовательно, могут быть созданы в расширениях на C. Также есть PyIntpArrType_Type и PyUIntpArrType_Type, которые являются простыми заменами одного из целочисленных типов, которые могут хранить указатель на платформе. Структура этих скалярных объектов не раскрывается для кода C. Функция PyArray_ScalarAsCtype (..) может быть использована для извлечения значения типа C из скаляра массива, а функция PyArray_Scalar (…) — для создания скаляра массива из значения C.

Другие структуры C

Несколько новых структур C оказались полезными при разработке NumPy. Эти структуры C используются, по крайней мере, в одном вызове C-API и поэтому документированы здесь. Основная причина определения этих структур — упрощение использования Python ParseTuple C-API для преобразования объектов Python в полезные объекты C.

PyArray_Dims

typePyArray_Dims

Эта структура очень полезна при интерпретации информации о форме и/или шагах. Структура:

typedef struct {
    npy_intp *ptr;
    int len;
} PyArray_Dims;

Члены этой структуры:

npy_intp*ptr

Указатель на список целых чисел (npy_intp), которые обычно представляют форму массива или шаги массива.

intlen

Длина списка целых чисел. Предполагается, что доступ к ptr[0] до ptr[len-1] безопасен.

PyArray_Chunk

typePyArray_Chunk

Это эквивалентно структуре объекта буфера в Python до члена ptr. На 32-битных платформах (т.е., если NPY_SIZEOF_INT == NPY_SIZEOF_INTP), член len также соответствует эквивалентному члену объекта буфера. Он полезен для представления общего сегмента памяти.

typedef struct {
    PyObject_HEAD
    PyObject *base;
    void *ptr;
    npy_intp len;
    int flags;
} PyArray_Chunk;

Члены:

PyObject*base

Объект Python, из которого берётся этот сегмент памяти. Необходим для правильного учёта памяти.

void*ptr

Указатель на начало сегмента памяти.

npy_intplen

Длина сегмента в байтах.

intflags

Любые флаги данных (например, NPY_ARRAY_WRITEABLE), которые следует использовать для интерпретации памяти.

PyArrayInterface

См. также

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

typePyArrayInterface

Структура PyArrayInterface определена для того, чтобы NumPy и другие модули расширений могли использовать протокол быстрого интерфейса массивов. Метод __array_struct__ объекта, поддерживающего протокол быстрого интерфейса массивов, должен возвращать PyCapsule, содержащий указатель на структуру PyArrayInterface с соответствующими деталями массива. После создания нового массива атрибут должен быть DECREF'd, что освободит структуру PyArrayInterface. Не забудьте INCREF объект (чьё значение атрибута __array_struct__ было получено) и укажите, что базовый член нового PyArrayObject ссылается на этот же объект. Таким образом, память для массива будет управляться правильно.

typedef struct {
    int two;
    int nd;
    char typekind;
    int itemsize;
    int flags;
    npy_intp *shape;
    npy_intp *strides;
    void *data;
    PyObject *descr;
} PyArrayInterface;
inttwo

целое число 2 в качестве проверки.

intnd

число измерений в массиве.

chartypekind

Символ, указывающий тип массива в соответствии с соглашениями типов: ‘t’ -> битовое поле, ‘b’ -> логическое, ‘i’ -> целое со знаком, ‘u’ -> целое без знака, ‘f’ -> с плавающей точкой, ‘c’ -> комплексное с плавающей точкой, ‘O’ -> объект, ‘S’ -> (байтовый) строка, ‘U’ -> юникод, ‘V’ -> пусто.

intitemsize

Количество байтов, необходимое для каждого элемента в массиве.

intflags

Любые биты NPY_ARRAY_C_CONTIGUOUS (1), NPY_ARRAY_F_CONTIGUOUS (2), NPY_ARRAY_ALIGNED (0x100), NPY_ARRAY_NOTSWAPPED (0x200) или NPY_ARRAY_WRITEABLE (0x400) для указания информации о данных. Флаги NPY_ARRAY_ALIGNED, NPY_ARRAY_C_CONTIGUOUS и NPY_ARRAY_F_CONTIGUOUS фактически могут быть определены по другим параметрам. Флаг NPY_ARR_HAS_DESCR (0x800) также может быть установлен для указания объектам, потребляющим интерфейс массива версии 3, что член descr структуры присутствует (он будет проигнорирован объектами, потребляющими интерфейс массива версии 2).

npy_intp*shape

Массив, содержащий размер массива в каждом измерении.

npy_intp*strides

Массив, содержащий количество байтов, которые нужно переместить, чтобы перейти к следующему элементу в каждом измерении.

void*data

Указатель на первый элемент массива.

PyObject*descr

Объект Python, описывающий тип данных более подробно (такой же, как ключ descr в __array_interface__). Этот член может быть NULL если typekind и itemsize предоставляют достаточно информации. Этот член также игнорируется, если в флаге NPY_ARR_HAS_DESCR установлен флаг flags.

Внутренние структуры

Внутренне код использует дополнительные объекты Python, главным образом для управления памятью. Эти типы не доступны напрямую из Python и не представлены в C-API. Они включены здесь только для полноты и помощи в понимании кода.

typePyUFuncLoopObject

Свободная оболочка для C-структуры, содержащей информацию, необходимую для циклов. Это полезно, если вы пытаетесь понять код циклов ufunc. PyUFuncLoopObject — связанная C-структура. Она определена в заголовочном файле ufuncobject.h.

typePyUFuncReduceObject

Свободная оболочка для C-структуры, содержащей информацию, необходимую для методов reduce-подобных ufunc. Это полезно, если вы пытаетесь понять код reduce, accumulate и reduce-at. PyUFuncReduceObject — связанная C-структура. Она определена в заголовочном файле ufuncobject.h.

typePyUFunc_Loop1d

Простой связанный список C-структур, содержащих информацию, необходимую для определения одномерного цикла для ufunc для каждой определенной сигнатуры пользовательского типа данных.

PyTypeObjectPyArrayMapIter_Type

Обработка расширенных индексов выполняется с помощью этого типа Python. Это просто свободная оболочка вокруг C-структуры, содержащей переменные, необходимые для индексации массивов с расширенными индексами. Связанная C-структура, PyArrayMapIterObject, полезна, если вы пытаетесь понять код отображения расширенных индексов. Она определена в заголовочном файле arrayobject.h Этот тип не доступен из Python и может быть заменён C-структурой. В качестве типа Python он использует управление памятью с подсчётом ссылок.

© 2005–2022 NumPy Developers
Licensed under the 3-clause BSD License.
https://numpy.org/doc/1.21/reference/c-api/types-and-structures.html

Spec-Zone.ru

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