Типы Python и C-структуры
В коде на C определены несколько новых типов. Большинство из них доступны из Python, но некоторые не экспонированы из-за ограниченного использования. Каждый новый тип Python связан со структурой PyObject * с внутренней структурой, которая включает указатель на «таблицу методов», определяющую поведение нового объекта в Python. Когда вы получаете объект Python в коде C, вы всегда получаете указатель на структуру PyObject. Поскольку структура PyObject очень общая и определяет только PyObject_HEAD, сама по себе она не очень интересна. Однако разные объекты содержат больше деталей после PyObject_HEAD (но вам нужно выполнить приведение к нужному типу, чтобы получить к ним доступ — или использовать функции-обработчики или макросы).
Определенные новые типы Python
Типы Python функционально эквивалентны классам в Python в C. Создав новый тип Python, вы делаете доступным новый объект для Python. Объект ndarray является примером нового типа, определенного на C. Новые типы определяются на C двумя основными этапами:
- создание C-структуры (обычно с именем
Py{Name}Object), которая бинарно совместима со структуройPyObject, но содержит дополнительную информацию, необходимую для этого конкретного объекта; - заполнение таблицы
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.
-
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
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-длинных последовательности, складывает их и помещает результат в элемент, указанныйoparr. Начало двух последовательностей указано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 -
Массив из
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 -
где
— число измерений в базовом массиве.
-
npy_intp index -
Текущий одномерный индекс в массиве.
-
npy_intp size -
Общий размер базового массива.
-
npy_intp *coordinates -
Индекс в массиве размерностью
.
-
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 -
Этот тип предоставляет итератор, который обобщает концепцию вещания. Он позволяет
массивам вещаться вместе, так что цикл продвигается в стиле 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