Spec-Zone.ru › NumPy 1.20

Типы 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

PyArray_Type

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

END_OF_DOCUMENT_MARKER
PyArrayObject
NPY_AO

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

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, этот член — указатель на первый элемент массива. Этот указатель может (и обычно должен) быть преобразован к типу данных массива.

int nd

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

npy_intp dimensions

Массив целых чисел, предоставляющий форму по каждому измерению, при условии, что 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.

int flags

На который указывает макрос 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

PyArrayDescr_Type

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

PyArray_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.

char kind

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

char type

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

char byteorder

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

char flags

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

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).

int PyDataType_FLAGCHK(PyArray_Descr *dtype, int flags)

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

int PyDataType_REFCHK(PyArray_Descr *dtype)

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

int type_num

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

int elsize

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

int alignment

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

PyArray_ArrayDescr *subarray

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

PyArray_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

Метаданные об этом типе данных.

NpyAuxData *c_metadata

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

npy_hash_t
npy_hash_t *hash

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

PyArray_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 могут (и должны) обрабатывать невыровненные массивы. Другие функции требуют выровненные сегменты памяти.

void cast(void *from, void *to, npy_intp n, void *fromarr, void *toarr)

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

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

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

int setitem(PyObject *item, void *data, void *arr)

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

void copyswapn(void *dest, npy_intp dstride, void *src, npy_intp sstride, npy_intp n, int swap, void *arr)
void copyswap(void *dest, void *src, int swap, void *arr)

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

int compare(const void* d1, const void* d2, void* arr)

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

int argmax(void* data, npy_intp n, npy_intp* max_ind, void* arr)

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

void dotfunc(void* ip1, npy_intp is1, void* ip2, npy_intp is2, void* op, npy_intp n, void* arr)

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

int scanfunc(FILE* fd, void* ip, void* arr)

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

int fromstr(char* str, void* ip, char** endptr, void* arr)

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

npy_bool nonzero(void* data, void* arr)

Указатель на функцию, которая возвращает ИСТИНА, если элемент arr по адресу data не равен нулю. Эта функция может обрабатывать невыровненные массивы.

void fill(void* data, npy_intp length, void* arr)

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

void fillwithscalar(void* buffer, npy_intp length, void* value, void* arr)

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

int sort(void* start, npy_intp length, void* arr)

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

int argsort(void* start, npy_intp* result, npy_intp length, void *arr)

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

PyObject *castdict

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

NPY_SCALARKIND scalarkind(PyArrayObject* arr)

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

int **cancastscalarkindto

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

int *cancastto

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

void fastclip(void *in, npy_intp n_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, но не оба.

void fastputmask(void *in, void *mask, npy_intp n_in, void *values, npy_intp nv)

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

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

void fasttake(void *dest, void *src, npy_intp *indarray, npy_intp nindarray, npy_intp n_outer, npy_intp m_middle, npy_intp nelem, NPY_CLIPMODE clipmode)

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

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

int argmin(void* data, npy_intp n, 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

PyUFunc_Type

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

PyUFuncObject

Ядро 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;
int nin

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

int nout

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

int nargs

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

int identity

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

void functions(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 используется, если дополнительные данные не нужны. Несколько вызовов функций API для UFuncs — это просто 1-мерные векторные циклы, которые используют эти дополнительные данные для получения указателя на фактическую вызываемую функцию.

int ntypes

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

int reserved1

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

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.

int core_enabled

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

int core_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.

npy_uint32 op_flags

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

npy_uint32 iter_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

Тождество для reduce, когда PyUFuncObject.identity равно PyUFunc_IdentityValue.

PyArrayIter_Type и PyArrayIterObject

PyArrayIter_Type

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

PyArrayIterObject

Структура C, соответствующая объекту PyArrayIter_Type, — это PyArrayIterObject. PyArrayIterObject используется для отслеживания указателя в N-мерном массиве. Он содержит связанную информацию, используемую для быстрого перемещения по массиву. Указатель можно изменять тремя основными способами: 1) переходить к следующей позиции в массиве в стиле C, 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;
int nd_m1

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

npy_intp index

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

npy_intp size

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

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-мерного индекса из одномерного индекса. Он содержит необходимые произведения измерений.

PyArrayObject *ao

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

char *dataptr

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

npy_bool contiguous

Этот флаг имеет значение 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

PyArrayMultiIter_Type

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

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

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

npy_intp size

Общий размер вещания.

npy_intp index

Текущий (одномерный) индекс в результате вещания.

int nd

Количество измерений в результате вещания.

npy_intp *dimensions

Форма результата вещания (используются только nd слотов).

PyArrayIterObject **iters

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

PyArrayNeighborhoodIter_Type и PyArrayNeighborhoodIterObject

PyArrayNeighborhoodIter_Type

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

PyArrayNeighborhoodIterObject

Структура 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

PyArrayFlags_Type

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

PyArrayFlagsObject
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

PyArray_Dims

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

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

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

npy_intp *ptr

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

int len

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

PyArray_Chunk

PyArray_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_intp len

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

int flags

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

PyArrayInterface

См. также

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

PyArrayInterface

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

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

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

int nd

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

char typekind

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

int itemsize

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

int flags

Любые биты 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. Они включены здесь только для полноты и помощи в понимании кода.

PyUFuncLoopObject

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

PyUFuncReduceObject

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

PyUFunc_Loop1d

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

PyArrayMapIter_Type

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

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

Spec-Zone.ru

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