Типы 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
- PyTypeObjectPyArray_Type
-
Тип Python ndarray —
PyArray_Type. В C каждый ndarray — указатель на структуруPyArrayObject. Член ob_type этой структуры содержит указатель на типPyArray_Type.
- typePyArrayObject
- typeNPY_AO
-
Структура
PyArrayObjectC содержит всю необходимую информацию для массива. Все экземпляры ndarray (и его подклассов) будут иметь эту структуру. Для будущей совместимости члены этой структуры обычно должны быть доступны с помощью предоставленных макросов. Если вам нужен более короткий имя, вы можете использоватьNPY_AO(устаревший), который определен как эквивалентныйPyArrayObject. Прямой доступ к полям структуры устарел. ИспользуйтеPyArray_*(arr)вместо этого. Начиная с NumPy 1.20, размер этой структуры не считается частью NumPy ABI (см. примечание в конце списка членов).typedef struct PyArrayObject { PyObject_HEAD char *data; int nd; npy_intp *dimensions; npy_intp *strides; PyObject *base; PyArray_Descr *descr; int flags; PyObject *weakreflist; /* version dependend private members */ } PyArrayObject;- PyObject_HEAD
-
Это необходимо для всех объектов Python. Он состоит (по крайней мере) из счетчика ссылок (
ob_refcnt) и указателя на тип объекта (ob_type). (Другие элементы также могут присутствовать, если Python был скомпилирован со специальными опциями. Смотрите Include/object.h в исходном коде Python для получения дополнительной информации). Член ob_type указывает на объект типа Python.
- char*data
-
Доступно через
PyArray_DATA, этот член данных — указатель на первый элемент массива. Этот указатель можно (и обычно следует) перевести в тип данных массива.
- intnd
-
Целое число, определяющее количество измерений для этого массива. Когда nd равно 0, массив иногда называют массивом ранга 0. Такие массивы имеют неопределенные размеры и шаги и не могут быть обработаны. Макрос
PyArray_NDIM, определенный вndarraytypes.h, указывает на этот член данных.NPY_MAXDIMS— это максимальное количество измерений для любого массива.
- npy_intpdimensions
-
Массив целых чисел, предоставляющий форму в каждом измерении, пока nd \(\geq\) 1. Целое число всегда достаточно велико, чтобы содержать указатель на платформе, поэтому размер измерения ограничен только памятью. Макрос
PyArray_DIMSассоциирован с этим членом данных.
- npy_intp*strides
-
Массив целых чисел, предоставляющий для каждого измерения количество байтов, которые необходимо пропустить, чтобы перейти к следующему элементу в этом измерении. Ассоциировано с макросом
PyArray_STRIDES.
- PyObject*base
-
На который указывает
PyArray_BASE, этот член используется для хранения указателя на другой объект Python, связанный с этим массивом. Существует два случая использования:- Если этот массив не владеет собственной памятью, то base указывает на объект Python, который им владеет (возможно, другой объект массива)
- Если для этого массива установлен (устаревший) флаг
NPY_ARRAY_UPDATEIFCOPYилиNPY_ARRAY_WRITEBACKIFCOPY, то этот массив является рабочей копией «неправильного» массива.
При вызове
PyArray_ResolveWritebackIfCopy, массив, на который указывает base, будет обновлен содержимым этого массива.
- PyArray_Descr*descr
-
Указатель на объект описателя типа данных (см. ниже). Объект описателя типа данных — это экземпляр нового встроенного типа, который позволяет описывать память в общем виде. Существует структура описателя для каждого поддерживаемого типа данных. Эта структура описателя содержит полезную информацию о типе, а также указатель на таблицу указателей на функции для реализации конкретных функций. Как следует из названия, она связана с макросом
PyArray_DESCR.
- intflags
-
На который указывает макрос
PyArray_FLAGS, этот член данных представляет флаги, указывающие, как интерпретировать память, на которую указывает data. Возможные флаги:NPY_ARRAY_C_CONTIGUOUS,NPY_ARRAY_F_CONTIGUOUS,NPY_ARRAY_OWNDATA,NPY_ARRAY_ALIGNED,NPY_ARRAY_WRITEABLE,NPY_ARRAY_WRITEBACKIFCOPYиNPY_ARRAY_UPDATEIFCOPY.
- PyObject*weakreflist
-
Этот член позволяет объектам массива иметь слабые ссылки (с использованием модуля weakref).
Примечание
Дополнительные члены считаются закрытыми и зависят от версии. Если размер структуры важен для вашего кода, необходимо проявлять особую осторожность. Возможным случаем использования, когда это актуально, является наследование в C. Если ваш код полагается на
sizeof(PyArrayObject)как на постоянную величину, вам необходимо добавить следующую проверку во время импорта:if (sizeof(PyArrayObject) < PyArray_Type.tp_basicsize) { PyErr_SetString(PyExc_ImportError, "Binary incompatibility with NumPy, must recompile/update X."); return NULL; }Чтобы ваш код не нужно было компилировать для определенной версии NumPy, вы можете добавить константу, оставив место для изменений в NumPy. Решение, гарантирующее совместимость с любой будущей версией NumPy, требует использования вычисления смещения и размера выделения во время выполнения.
- PyObject_HEAD
PyArrayDescr_Type и PyArray_Descr
- PyTypeObjectPyArrayDescr_Type
-
Тип
PyArrayDescr_Type— это встроенный тип объектов описателей типа данных, используемых для описания того, как следует интерпретировать байты, составляющие массив. Существует 21 статически определенный объектPyArray_Descrдля встроенных типов данных. Хотя они участвуют в подсчете ссылок, их счетчик ссылок никогда не должен достигать нуля. Также поддерживается динамическая таблица объектов пользовательскихPyArray_Descr. После «регистрации» объекта описателя типа данных его также не следует удалять. ФункцияPyArray_DescrFromType(…) может использоваться для извлечения объектаPyArray_Descrиз перечислимого номера типа (встроенного или пользовательского).
- typePyArray_Descr
-
Структура
PyArray_Descrлежит в основеPyArrayDescr_Type. Хотя она описана здесь для полноты, её следует считать внутренней для NumPy и манипулировать с помощью функций или макросовPyArrayDescr_*илиPyDataType*. Размер этой структуры может меняться в разных версиях NumPy. Чтобы обеспечить совместимость:- Никогда не объявляйте не-указатель экземпляра структуры.
- Никогда не выполняйте арифметику указателей.
- Никогда не используйте
sizof(PyArray_Descr)
Она имеет следующую структуру:
typedef struct { PyObject_HEAD PyTypeObject *typeobj; char kind; char type; char byteorder; char flags; int type_num; int elsize; int alignment; PyArray_ArrayDescr *subarray; PyObject *fields; PyObject *names; PyArray_ArrFuncs *f; PyObject *metadata; NpyAuxData *c_metadata; npy_hash_t hash; } PyArray_Descr;- PyTypeObject*typeobj
-
Указатель на тип объекта, соответствующий Python-типу элементов этого массива. Для встроенных типов это указывает на соответствующий скаляр массива. Для типов, определённых пользователем, это должно указывать на объект пользовательского типа. Этот тип объекта может унаследовать или нет от скаляров массива. Если он не наследует от скаляров массива, то флаги
NPY_USE_GETITEMиNPY_USE_SETITEMдолжны быть установлены в членеflags.
- charkind
-
Символьный код, указывающий тип массива (используя обозначение типов в строке интерфейса массива). ‘b’ представляет булевы значения, ‘i’ — целые со знаком, ‘u’ — целые без знака, ‘f’ — числа с плавающей точкой, ‘c’ — комплексные числа с плавающей точкой, ‘S’ — 8-битовые нуль-терминированные байты, ‘U’ — 32-битовые/символьные строки Unicode, и ‘V’ — произвольные.
- chartype
-
Традиционный символьный код, указывающий тип данных.
- charbyteorder
-
Символ, указывающий порядок байтов: ‘>’ (большая эндианность), ‘<’ (малая эндианность), ‘=’ (родной), ‘|’ (не имеет значения, игнорировать). Все встроенные типы данных имеют порядок байтов ‘=’.
- charflags
-
Флаги типа данных, определяющие, обладает ли тип данных поведением, подобным массиву объектов. Каждый бит в этом члене является флагом, имеющим следующие названия:
- NPY_ITEM_REFCOUNT
-
Указывает, что элементы этого типа данных должны быть подсчитаны со ссылкой (с использованием
Py_INCREFиPy_DECREF).
- NPY_ITEM_HASOBJECT
-
То же, что и
NPY_ITEM_REFCOUNT.
- NPY_LIST_PICKLE
-
Указывает, что массивы этого типа данных должны быть преобразованы в список перед сериализацией.
- NPY_ITEM_IS_POINTER
-
Указывает, что элемент является указателем на другие данные.
- NPY_NEEDS_INIT
-
Указывает, что память для этого типа данных должна быть инициализирована (обнулена) при создании.
- NPY_NEEDS_PYAPI
-
Указывает, что этому типу данных нужен Python C-API при доступе (поэтому не отпускайте GIL, если требуется доступ к массиву).
- NPY_USE_GETITEM
-
При доступе к массиву используйте указатель функции
f->getitemвместо стандартного преобразования в скаляр массива. Нужно использовать, если вы не определяете скаляр массива для работы с типом данных.
- NPY_USE_SETITEM
-
При создании 0-мерного массива из скаляра массива используйте
f->setitemвместо стандартной копии из скаляра массива. Нужно использовать, если вы не определяете скаляр массива для работы с типом данных.
- NPY_FROM_FIELDS
-
Биты, унаследованные от родительского типа данных, если эти биты установлены в любом поле типа данных. В настоящее время (
NPY_NEEDS_INIT|NPY_LIST_PICKLE|NPY_ITEM_REFCOUNT|NPY_NEEDS_PYAPI).
- NPY_OBJECT_DTYPE_FLAGS
-
Биты, установленные для типа данных объекта: (
NPY_LIST_PICKLE|NPY_USE_GETITEM|NPY_ITEM_IS_POINTER|NPY_ITEM_REFCOUNT|NPY_NEEDS_INIT|NPY_NEEDS_PYAPI).
- intPyDataType_FLAGCHK(PyArray_Descr*dtype, intflags)
-
Возвращает истину, если все заданные флаги установлены для объекта типа данных.
- intPyDataType_REFCHK(PyArray_Descr*dtype)
-
Эквивалентно
PyDataType_FLAGCHK(dtype,NPY_ITEM_REFCOUNT).
- NPY_ITEM_REFCOUNT
- inttype_num
-
Число, которое однозначно идентифицирует тип данных. Для новых типов данных это число назначается при регистрации типа данных.
- intelsize
-
Для типов данных, которые всегда имеют одинаковый размер (например, long), здесь хранится размер типа данных. Для гибких типов данных, где разные массивы могут иметь различный размер элемента, это значение должно быть 0.
- intalignment
-
Число, предоставляющее информацию об выравнивании для этого типа данных. В частности, оно показывает, насколько далеко от начала двухелементной структуры (первым элементом которой является
char), компилятор помещает элемент этого типа:offsetof(struct {char c; type v;}, v)
- PyArray_ArrayDescr*subarray
-
Если это не
NULL, то этот описатель типа данных является C-стильным контигуозным массивом другого описателя типа данных. Другими словами, каждый элемент, описываемый этим описателем, фактически является массивом некоторого другого базового описателя. Это наиболее полезно в качестве описателя типа данных для поля в другом описателе типа данных. Член fields должен бытьNULL, если это неNULL(член fields базового описателя может быть неNULL, однако).- typePyArray_ArrayDescr
-
typedef struct { PyArray_Descr *base; PyObject *shape; } PyArray_ArrayDescr;- PyArray_Descr*base
-
Объект описателя типа базового типа.
- PyObject*shape
-
Форма (всегда C-стильная контигуозная) подмассива в виде кортежа Python.
- PyArray_Descr*base
- typePyArray_ArrayDescr
- PyObject*fields
-
Если это не NULL, то этот описатель типа данных имеет поля, описанные словарем Python, ключами которого являются имена (а также заголовки, если заданы), а значениями — кортежи, описывающие поля. Запомните, что описатель типа данных всегда описывает фиксированный набор байтов. Поле — это именованная подобласть этого общего, фиксированного по длине набора. Поле описывается кортежем, состоящим из другого описателя типа данных и смещения байтов. По желанию кортеж может содержать заголовок, который обычно является строкой Python. Эти кортежи помещаются в этот словарь с ключом по имени (а также по заголовку, если он задан).
- PyObject*names
-
Упорядоченный кортеж имён полей. Он равен NULL, если поля не определены.
- PyArray_ArrFuncs*f
-
Указатель на структуру, содержащую функции, которые тип должен реализовать для внутренних функций. Эти функции не являются теми же, что универсальные функции (ufuncs), описанные позже. Их сигнатуры могут варьироваться произвольным образом.
- PyObject*metadata
-
Метаданные об этом dtype.
- NpyAuxData*c_metadata
-
Метаданные, специфичные для реализации dtype на C. Добавлено для NumPy 1.7.0.
- typenpy_hash_t
- npy_hash_t*hash
-
В настоящее время не используется. Зарезервировано для будущего использования в кэшировании хеш-значений.
- PyArray_ArrayDescr*subarray
- typePyArray_ArrFuncs
-
Функции, реализующие внутренние возможности. Не все указатели на эти функции должны быть определены для данного типа. Требуемые члены —
nonzero,copyswap,copyswapn,setitem,getitem, иcast. Предполагается, что они неNULLиNULLзаписи приведут к сбою программы. Другие функции могут бытьNULL, что просто означает уменьшенную функциональность для этого типа данных. (Кроме того, функция nonzero будет заполнена по умолчанию, если онаNULLпри регистрации пользовательского типа данных).typedef struct { PyArray_VectorUnaryFunc *cast[NPY_NTYPES]; PyArray_GetItemFunc *getitem; PyArray_SetItemFunc *setitem; PyArray_CopySwapNFunc *copyswapn; PyArray_CopySwapFunc *copyswap; PyArray_CompareFunc *compare; PyArray_ArgFunc *argmax; PyArray_DotFunc *dotfunc; PyArray_ScanFunc *scanfunc; PyArray_FromStrFunc *fromstr; PyArray_NonzeroFunc *nonzero; PyArray_FillFunc *fill; PyArray_FillWithScalarFunc *fillwithscalar; PyArray_SortFunc *sort[NPY_NSORTS]; PyArray_ArgSortFunc *argsort[NPY_NSORTS]; PyObject *castdict; PyArray_ScalarKindFunc *scalarkind; int **cancastscalarkindto; int *cancastto; PyArray_FastClipFunc *fastclip; /* deprecated */ PyArray_FastPutmaskFunc *fastputmask; /* deprecated */ PyArray_FastTakeFunc *fasttake; /* deprecated */ PyArray_ArgFunc *argmin; } PyArray_ArrFuncs;В описании указателей функций используется понятие «вежливого сегмента». Вежливый сегмент — это сегмент, выровненный и в родном порядке байтов для типа данных. Функции
nonzero,copyswap,copyswapn,getitem, иsetitemмогут (и должны) обрабатывать массивы с неправильным поведением. Другие функции требуют вежливых сегментов памяти.- voidcast(void*from, void*to, npy_intpn, void*fromarr, void*toarr)
-
Массив указателей на функции для преобразования из текущего типа во все другие встроенные типы. Каждая функция преобразует непрерывный, выровненный и не инвертированный буфер, указанный по адресу from, в непрерывный, выровненный и не инвертированный буфер, указанный по адресу to. Количество элементов для преобразования задано n, а аргументы fromarr и toarr интерпретируются как PyArrayObjects для гибких массивов для получения информации о размере элемента.
- PyObject*getitem(void*data, void*arr)
-
Указатель на функцию, которая возвращает стандартный объект Python из одного элемента объекта массива arr, на который указывает data. Эта функция должна уметь правильно обрабатывать «неправильно ведущиеся» (невыровненные и/или инвертированные) массивы.
- intsetitem(PyObject*item, void*data, void*arr)
-
Указатель на функцию, которая помещает объект Python item в массив arr в позиции, на которую указывает data. Эта функция обрабатывает «неправильно ведущиеся» массивы. При успешном выполнении возвращается ноль, в противном случае — минус один (и возникает ошибка Python).
- voidcopyswapn(void*dest, npy_intpdstride, void*src, npy_intpsstride, npy_intpn, intswap, void*arr)
- voidcopyswap(void*dest, void*src, intswap, void*arr)
-
Эти члены — указатели на функции для копирования данных из src в dest и инвертирования байтов, если указано. Значение arr используется только для гибких (
NPY_STRING,NPY_UNICODEиNPY_VOID) массивов (и получено изarr->descr->elsize). Вторая функция копирует одно значение, а первая циклится по n значениям с заданными шагами. Эти функции могут обрабатывать данные src с неправильным поведением. Если src равно NULL, то копирование не выполняется. Если swap равно 0, то инвертирование байтов не происходит. Предполагается, что dest и src не перекрываются. Если они перекрываются, то сначала используйтеmemmove(…), а затемcopyswap(n)сsrcравным NULL.
- intcompare(constvoid*d1, constvoid*d2, void*arr)
-
Указатель на функцию, которая сравнивает два элемента массива,
arr, на которые указываютd1иd2. Эта функция требует вежливых (выровненных и не инвертированных) массивов. Возвращаемое значение равно 1, если *d1> *d2, 0, если *d1== *d2, и -1, если *d1< *d2. Объект массиваarrиспользуется для получения информации о размере элемента и полях для гибких массивов.
- intargmax(void*data, npy_intpn, npy_intp*max_ind, void*arr)
-
Указатель на функцию, которая возвращает индекс максимального из
nэлементов вarr, начиная с элемента, на который указываетdata. Эта функция требует, чтобы сегмент памяти был непрерывным и вежливым. Возвращаемое значение всегда равно 0. Индекс максимального элемента возвращается вmax_ind.
- voiddotfunc(void*ip1, npy_intpis1, void*ip2, npy_intpis2, void*op, npy_intpn, void*arr)
-
Указатель на функцию, которая умножает две
n-длинные последовательности, складывает их и помещает результат в элемент, на который указываетopвarr. Начало двух последовательностей указано по адресамip1иip2. Для перехода к следующему элементу в каждой последовательности требуется переход наis1иis2байт соответственно. Эта функция требует вежливой (но не обязательно непрерывной) памяти.
- intscanfunc(FILE*fd, void*ip, void*arr)
-
Указатель на функцию, которая считывает (в стиле scanf) один элемент соответствующего типа из дескриптора файла
fdв память массива, на которую указываетip. Массив предполагается вежливым. Последний аргументarr— массив, в который производится считывание. Возвращает количество успешно присвоенных аргументов (может быть нулевым в случае неудачного соответствия до назначения первого аргумента) или EOF, если ошибка ввода-вывода возникает до назначения первого аргумента. Эта функция должна вызываться без блокировки Python GIL и должна захватывать её для сообщения об ошибках.
- voidcast(void*from, void*to, npy_intpn, void*fromarr, void*toarr)
- intfromstr(char*str, void*ip, char**endptr, void*arr)
-
Указатель на функцию, которая преобразует строку, на которую указывает
str, в один элемент соответствующего типа и помещает его в место памяти, на которое указываетip. После завершения преобразования,*endptrуказывает на оставшуюся часть строки. Последний аргументarr— это массив, на который указывает ip (необходим для типов данных переменной длины). Возвращает 0 при успехе или -1 при ошибке. Требуется вежливый массив. Эта функция должна вызываться без блокировки Python GIL, и должна захватить её для сообщения об ошибке.
- npy_boolnonzero(void*data, void*arr)
-
Указатель на функцию, которая возвращает TRUE, если элемент
arr, на который указываетdata, не равен нулю. Эта функция может работать с некорректными массивами.
- voidfill(void*data, npy_intplength, void*arr)
-
Указатель на функцию, заполняющую непрерывный массив заданной длины данными. Первые два элемента массива должны быть уже заполнены. Из этих двух значений будет вычислена разность, и значения с элемента 3 до конца будут вычислены путём многократного добавления этой вычисленной разности. Буфер данных должен быть корректным.
- voidfillwithscalar(void*buffer, npy_intplength, void*value, void*arr)
-
Указатель на функцию, заполняющую непрерывный
bufferзаданнойlengthодним скалярным значениемvalue, адрес которого указан. Последний аргумент — массив, необходимый для получения размера элемента для массивов переменной длины.
- intsort(void*start, npy_intplength, void*arr)
-
Массив указателей на функции для определённого алгоритма сортировки. Конкретный алгоритм сортировки определяется ключом (на данный момент
NPY_QUICKSORT,NPY_HEAPSORTиNPY_MERGESORTопределены). Эти сортировки выполняются на месте, предполагая непрерывные и выровненные данные.
- intargsort(void*start, npy_intp*result, npy_intplength, void*arr)
-
Массив указателей на функции сортировки для этого типа данных. Доступны те же алгоритмы сортировки, что и для sort. Индексы, дающие сортировку, возвращаются в
result(который должен быть инициализирован индексами от 0 доlength-1включительно).
- PyObject*castdict
-
Либо
NULL, либо словарь, содержащий функции низкоуровневого преобразования для типов данных, определённых пользователем. Каждая функция обернута в PyCapsule* и индексируется по номеру типа данных.
- NPY_SCALARKINDscalarkind(PyArrayObject*arr)
-
Функция для определения того, как скаляры этого типа должны интерпретироваться. Аргумент —
NULLили 0-мерный массив, содержащий данные (если это необходимо для определения типа скаляра). Значение возврата должно быть типаNPY_SCALARKIND.
- int**cancastscalarkindto
-
Либо
NULLили массив указателейNPY_NSCALARKINDS. Эти указатели должны быть либоNULLили указателем на массив целых чисел (завершённыйNPY_NOTYPE), указывающий типы данных, к которым скаляр этого типа указанного вида может быть безопасно преобразован (обычно это означает без потери точности).
- int*cancastto
-
Либо
NULLили массив целых чисел (завершённыйNPY_NOTYPE), указывающий типы данных, к которым этот тип данных может быть безопасно преобразован (обычно это означает без потери точности).
- voidfastclip(void*in, npy_intpn_in, void*min, void*max, void*out)
-
Устарело начиная с версии 1.17: Использование этой функции выдаст предупреждение об устаревании, когда
np.clip. Вместо этой функции тип данных должен использоватьPyUFunc_RegisterLoopForDescrдля подключения пользовательского цикла кnp.core.umath.clip,np.minimum, иnp.maximum.Устарело начиная с версии 1.19: Установка этой функции устарела и всегда должна быть
NULL, если установлена, она будет проигнорирована.Функция, которая считывает
n_inэлементов изin, и записывает вoutпрочитанное значение, если оно находится в пределах, указанныхminиmax, или соответствующий предел, если значение вне диапазона. Участки памяти должны быть непрерывными и корректными, и либоminилиmaxможет бытьNULL, но не оба.
- intfromstr(char*str, void*ip, char**endptr, void*arr)
- voidfastputmask(void*in, void*mask, npy_intpn_in, void*values, npy_intpnv)
-
Устарело начиная с версии 1.19: Установка этой функции устарела и всегда должна быть
NULL, если установлена, она будет проигнорирована.Функция, которая принимает указатель
inна массив изn_inэлементов, указательmaskна массивn_inбулевых значений и указательvalsна массив изnvэлементов. Элементы изvalsкопируются вinтам, где значение вmaskне равно нулю, с тилированиемvalsпо мере необходимости, еслиnv < n_in. Все массивы должны быть непрерывными и ведомыми.
- voidfasttake(void*dest, void*src, npy_intp*indarray, npy_intpnindarray, npy_intpn_outer, npy_intpm_middle, npy_intpnelem, NPY_CLIPMODEclipmode)
-
Устарело начиная с версии 1.19: Установка этой функции устарела и всегда должна быть
NULL, если установлена, она будет проигнорирована.Функция, которая принимает указатель
srcна непрерывный, ведомый сегмент, интерпретируемый как 3-мерный массив формы(n_outer, nindarray, nelem), указательindarrayна непрерывный, ведомый сегментm_middleцелочисленных индексов и указательdestна непрерывный, ведомый сегмент, интерпретируемый как 3-мерный массив формы(n_outer, m_middle, nelem). Индексы вindarrayиспользуются для индексированияsrcпо второму измерению и копирования соответствующих фрагментовnelemэлементов вdest.clipmode(которое может принимать значенияNPY_RAISE,NPY_WRAPилиNPY_CLIP) определяет, как будут обрабатываться индексы, меньшие 0 или большиеnindarray.
- intargmin(void*data, npy_intpn, npy_intp*min_ind, void*arr)
-
Указатель на функцию, которая извлекает индекс наименьшего из
nэлементов вarr, начиная с элемента, на который указываетdata. Эта функция требует, чтобы сегмент памяти был непрерывным и ведомым. Возвращаемое значение всегда равно 0. Индекс наименьшего элемента возвращается вmin_ind.
- voidfastputmask(void*in, void*mask, npy_intpn_in, void*values, npy_intpnv)
Тип PyArray_Type реализует многие функции Python objects, включая интерфейсы tp_as_number, tp_as_sequence, tp_as_mapping и tp_as_buffer. Также используется rich comparison вместе с поиском атрибутов нового стиля для членов (tp_members) и свойств (tp_getset). Тип PyArray_Type также может быть подтипизирован.
Подсказка
Методы tp_as_number используют общий подход для вызова любой функции, которая была зарегистрирована для обработки операции. При импорте _multiarray_umath module, он устанавливает числовые операции для всех массивов соответствующим функциям ufuncs. Этот выбор может быть изменён с помощью PyUFunc_ReplaceLoopBySignature. Методы tp_str и tp_repr также могут быть изменены с помощью PyArray_SetStringFunction.
PyUFunc_Type и PyUFuncObject
- PyTypeObjectPyUFunc_Type
-
Объект ufunc реализуется путём создания
PyUFunc_Type. Это очень простой тип, который реализует только базовое поведение getattribute, поведение печати и имеет поведение вызова, которое позволяет этим объектам действовать как функции. Основная идея ufunc заключается в хранении ссылки на быстрые 1-мерные (векторные) циклы для каждого типа данных, который поддерживает операцию. Эти одномерные циклы все имеют одинаковую сигнатуру и являются ключом к созданию новой функции ufunc. Они вызываются общим кодом циклов по мере необходимости для реализации N-мерной функции. Также определены некоторые общие 1-мерные циклы для плавающих и комплексных плавающих массивов, которые позволяют определить функцию ufunc с использованием одной скалярной функции (например, atanh).
- typePyUFuncObject
-
Ядро ufunc — это
PyUFuncObject, содержащее всю необходимую информацию для вызова подлежащих C-код циклов, выполняющих фактическую работу. Хотя оно описано здесь для полноты, его следует считать внутренним для NumPy и манипулировать им с помощьюPyUFunc_*функций. Размер этой структуры может изменяться в разных версиях NumPy. Чтобы обеспечить совместимость:- Никогда не объявляйте не-указатель экземпляра структуры.
- Никогда не выполняйте арифметику указателей.
- Никогда не используйте
sizeof(PyUFuncObject)
Она имеет следующую структуру:
typedef struct { PyObject_HEAD int nin; int nout; int nargs; int identity; PyUFuncGenericFunction *functions; void **data; int ntypes; int reserved1; const char *name; char *types; const char *doc; void *ptr; PyObject *obj; PyObject *userloops; int core_enabled; int core_num_dim_ix; int *core_num_dims; int *core_dim_ixs; int *core_offsets; char *core_signature; PyUFunc_TypeResolutionFunc *type_resolver; PyUFunc_LegacyInnerLoopSelectionFunc *legacy_inner_loop_selector; PyUFunc_MaskedInnerLoopSelectionFunc *masked_inner_loop_selector; npy_uint32 *op_flags; npy_uint32 *iter_flags; /* new in API version 0x0000000D */ npy_intp *core_dim_sizes; npy_uint32 *core_dim_flags; PyObject *identity_value; } PyUFuncObject;- intnin
-
Количество входных аргументов.
- intnout
-
Количество выходных аргументов.
- intnargs
-
Общее количество аргументов (nin + nout). Оно должно быть меньше
NPY_MAXARGS.
- intidentity
-
Либо
PyUFunc_One,PyUFunc_Zero,PyUFunc_MinusOne,PyUFunc_None,PyUFunc_ReorderableNone, илиPyUFunc_IdentityValueдля указания тождества для данной операции. Оно используется только для вызова типа reduce для пустого массива.
- voidfunctions(char**args, npy_intp*dims, npy_intp*steps, void*extradata)
-
Массив указателей на функции — по одному для каждого типа данных, поддерживаемого ufunc. Это векторный цикл, который вызывается для реализации подлежащей функции dims [0] раз. Первый аргумент, args, — это массив из nargs указателей на данные в памяти. Указатели на данные для входных аргументов идут первыми, а затем указатели на данные для выходных аргументов. Количество байтов, которое необходимо пропустить, чтобы перейти к следующему элементу в последовательности, задается соответствующей записью в массиве steps. Последний аргумент позволяет циклу получать дополнительную информацию. Это обычно используется для того, чтобы один универсальный векторный цикл мог использоваться для нескольких функций. В этом случае фактическая скалярная функция, которую нужно вызвать, передаётся в качестве extradata. Размер этого массива указателей на функции равен ntypes.
- void**data
-
Дополнительные данные, передаваемые в циклы 1-мерных векторов или
NULLесли дополнительные данные не нужны. Этот массив C должен иметь тот же размер (т.е. ntypes), что и массив функций.NULLиспользуется, если дополнительные данные не нужны. Несколько вызовов C-API для UFuncs — это просто циклы 1-мерных векторов, которые используют эти дополнительные данные для получения указателя на фактическую вызываемую функцию.
- intntypes
-
Количество поддерживаемых типов данных для ufunc. Это число определяет, сколько различных 1-мерных циклов (встроенных типов данных) доступно.
- intreserved1
-
Не используется.
- char*name
-
Строковое имя для ufunc. Используется динамически для построения атрибута __doc__ ufunc.
- char*types
-
Массив \(nargs \times ntypes\) 8-битных номеров типов, содержащих сигнатуру типа функции для каждого из поддерживаемых (встроенных) типов данных. Для каждой из ntypes функций соответствующий набор номеров типов в этом массиве показывает, как аргумент args должен интерпретироваться в цикле 1-мерного вектора. Эти номера типов не обязательно должны быть одного типа, и поддерживаются ufunc смешанных типов.
- char*doc
-
Документация для ufunc. Не должна содержать сигнатуру функции, так как она генерируется динамически при получении __doc__.
- void*ptr
-
Любая динамически выделенная память. В настоящее время используется для динамически созданных ufunc из python-функций для хранения места для членов types, data и name.
- PyObject*obj
-
Для ufunc, динамически созданных из python-функций, этот член содержит ссылку на подлежащую Python-функцию.
- PyObject*userloops
-
Словарь пользовательских циклов 1-мерных векторов (хранящихся как указатели CObject) для пользовательских типов. Пользователь может зарегистрировать цикл для любого пользовательского типа. Он извлекается по номеру типа. Номера типов, определённые пользователем, всегда больше
NPY_USERDEF.
- intcore_enabled
-
0 для скалярных ufunc; 1 для обобщённых ufunc
- intcore_num_dim_ix
-
Количество различных имён измерений ядра в сигнатуре
- int*core_num_dims
-
Количество измерений ядра каждого аргумента
- int*core_dim_ixs
-
Индексы измерений в уплощённом виде; индексы аргумента
kхранятся вcore_dim_ixs[core_offsets[k] : core_offsets[k] + core_numdims[k]]
- int*core_offsets
-
Позиция первого измерения ядра каждого аргумента в
core_dim_ixs, эквивалентно cumsum(core_num_dims)
- char*core_signature
-
Строка ядровой сигнатуры
- PyUFunc_TypeResolutionFunc*type_resolver
-
Функция, которая разрешает типы и заполняет массив dtypes для входных и выходных данных
- PyUFunc_LegacyInnerLoopSelectionFunc*legacy_inner_loop_selector
-
Функция, возвращающая внутренний цикл.
legacyв имени возникает потому, что для NumPy 1.6 планировалась лучшая версия. Эта версия ещё не появилась.
- void*reserved2
-
Для возможного будущего селектора циклов с другой сигнатурой.
- PyUFunc_MaskedInnerLoopSelectionFunc*masked_inner_loop_selector
-
Функция, возвращающая внутренний цикл с маской для ufunc
- npy_uint32op_flags
-
Переопределите значения флагов операндов по умолчанию для каждого операнда ufunc.
- npy_uint32iter_flags
-
Переопределите значения флагов nditer по умолчанию для ufunc.
Добавлен в версию API 0x0000000D
- npy_intp*core_dim_sizes
-
Для каждого уникального ядра измерения, возможный размер замороженный, если
UFUNC_CORE_DIM_SIZE_INFERREDравно0
- npy_uint32*core_dim_flags
-
Для каждого уникального ядра измерения, набор
UFUNC_CORE_DIM*флагов- UFUNC_CORE_DIM_CAN_IGNORE
-
если имя измерения заканчивается на
?
- UFUNC_CORE_DIM_SIZE_INFERRED
-
если размер измерения будет определён из операндов, а не из замороженной подписи
- UFUNC_CORE_DIM_CAN_IGNORE
- PyObject*identity_value
-
Идентичность для сокращения, когда
PyUFuncObject.identityравнаPyUFunc_IdentityValue.
- npy_uint32op_flags
Тип PyArrayIter_Type и PyArrayIterObject
- PyTypeObjectPyArrayIter_Type
-
Это объект-итератор, который упрощает итерацию по N-мерному массиву. Он является объектом, возвращаемым атрибутом flat ndarray. Он также широко используется во внутренних реализациях для итерации по N-мерному массиву. Интерфейс tp_as_mapping реализован таким образом, что к объекту-итератору можно обращаться по индексу (используя 1-мерную индексацию), а несколько методов реализованы через таблицу tp_methods. Этот объект реализует метод next и может быть использован везде, где в Python используется итератор.
- typePyArrayIterObject
-
C-структура, соответствующая объекту
PyArrayIter_Type, — этоPyArrayIterObject.PyArrayIterObjectиспользуется для отслеживания указателя в N-мерном массиве. Он содержит связанную информацию, используемую для быстрого перемещения по массиву. Указатель может быть скорректирован тремя основными способами: 1) перейти к следующей позиции в массиве в стиле C-contiguous, 2) перейти к произвольной N-мерной координате в массиве и 3) перейти к произвольному одномерному индексу в массиве. Члены структурыPyArrayIterObjectиспользуются в этих расчётах. Объекты-итераторы хранят свои собственные сведения о размерности и шагах массива. Это можно изменять по мере необходимости для «векторного вычисления» или для итерации только по определённым измерениям.typedef struct { PyObject_HEAD int nd_m1; npy_intp index; npy_intp size; npy_intp coordinates[NPY_MAXDIMS]; npy_intp dims_m1[NPY_MAXDIMS]; npy_intp strides[NPY_MAXDIMS]; npy_intp backstrides[NPY_MAXDIMS]; npy_intp factors[NPY_MAXDIMS]; PyArrayObject *ao; char *dataptr; npy_bool contiguous; } PyArrayIterObject;- intnd_m1
-
\(N-1\), где \(N\) — число измерений в базовом массиве.
- npy_intpindex
-
Текущий 1-мерный индекс в массиве.
- npy_intpsize
-
Общий размер базового массива.
- npy_intp*coordinates
-
N-мерный индекс в массиве.
- npy_intp*dims_m1
-
Размер массива минус 1 в каждом измерении.
- npy_intp*strides
-
Шаги массива. Сколько байтов необходимо перескочить, чтобы перейти к следующему элементу в каждом измерении.
- npy_intp*backstrides
-
Сколько байтов необходимо перескочить, чтобы вернуться к началу измерения от конца. Обратите внимание, что
backstrides[k] == strides[k] * dims_m1[k], но оно хранится здесь для оптимизации.
- npy_intp*factors
-
Этот массив используется для вычисления N-мерного индекса из 1-мерного индекса. Он содержит необходимые произведения измерений.
- PyArrayObject*ao
-
Указатель на базовый ndarray, который этот итератор создан для представления.
- char*dataptr
-
Этот член указывает на элемент в ndarray, указанный индексом.
- npy_boolcontiguous
-
Этот флаг имеет значение true, если базовый массив является
NPY_ARRAY_C_CONTIGUOUS. Он используется для упрощения вычислений, когда это возможно.
- intnd_m1
Более подробное описание использования итератора массива на уровне C приведено в последующих разделах. Как правило, вам не нужно заботиться о внутренней структуре объекта-итератора и взаимодействовать с ним только с помощью макросов PyArray_ITER_NEXT (it), PyArray_ITER_GOTO (it, dest) или PyArray_ITER_GOTO1D (it, index). Все эти макросы требуют аргумент it, который должен быть PyArrayIterObject*.
PyArrayMultiIter_Type и PyArrayMultiIterObject
- PyTypeObjectPyArrayMultiIter_Type
-
Этот тип предоставляет итератор, который обобщает концепцию вещания. Он позволяет \(N\) массивам быть объединёнными для вещания, так что цикл будет проходить по объединённому массиву в стиле C-contiguous. Соответствующая структура C —
PyArrayMultiIterObject, расположение памяти которой должно начинаться с любого объекта, obj, переданного в функциюPyArray_Broadcast(obj). Вещание выполняется путём корректировки итераторов массивов, так что каждый итератор представляет собой объединённую форму и размер, но его шаги корректируются, чтобы на каждой итерации использовался правильный элемент массива.
- typePyArrayMultiIterObject
-
typedef struct { PyObject_HEAD int numiter; npy_intp size; npy_intp index; int nd; npy_intp dimensions[NPY_MAXDIMS]; PyArrayIterObject *iters[NPY_MAXDIMS]; } PyArrayMultiIterObject;- intnumiter
-
Количество массивов, которые необходимо объединить для вещания в одну форму.
- npy_intpsize
-
Общий размер после вещания.
- npy_intpindex
-
Текущий (1-мерный) индекс в объединённом результате.
- intnd
-
Количество измерений в объединённом результате.
- npy_intp*dimensions
-
Форма объединённого результата (используются только
ndслоты).
- PyArrayIterObject**iters
-
Массив объектов итераторов, содержащий итераторы для массивов, которые необходимо объединить. После возврата итераторы корректируются для вещания.
- intnumiter
PyArrayNeighborhoodIter_Type и PyArrayNeighborhoodIterObject
- PyTypeObjectPyArrayNeighborhoodIter_Type
-
Это объект итератора, который упрощает циклирование по окрестности N-мерного массива.
- typePyArrayNeighborhoodIterObject
-
Структура C, соответствующая объекту
PyArrayNeighborhoodIter_Type, — этоPyArrayNeighborhoodIterObject.typedef struct { PyObject_HEAD int nd_m1; npy_intp index, size; npy_intp coordinates[NPY_MAXDIMS] npy_intp dims_m1[NPY_MAXDIMS]; npy_intp strides[NPY_MAXDIMS]; npy_intp backstrides[NPY_MAXDIMS]; npy_intp factors[NPY_MAXDIMS]; PyArrayObject *ao; char *dataptr; npy_bool contiguous; npy_intp bounds[NPY_MAXDIMS][2]; npy_intp limits[NPY_MAXDIMS][2]; npy_intp limits_sizes[NPY_MAXDIMS]; npy_iter_get_dataptr_t translate; npy_intp nd; npy_intp dimensions[NPY_MAXDIMS]; PyArrayIterObject* _internal_iter; char* constant; int mode; } PyArrayNeighborhoodIterObject;
PyArrayFlags_Type и PyArrayFlagsObject
- PyTypeObjectPyArrayFlags_Type
-
При получении атрибута флагов из Python, создаётся специальный встроенный объект этого типа. Этот специальный тип упрощает работу с разными флагами, предоставляя доступ к ним как к атрибутам или как к элементам словаря с именами флагов в качестве ключей.
- typePyArrayFlagsObject
-
typedef struct PyArrayFlagsObject { PyObject_HEAD PyObject *arr; int flags; } PyArrayFlagsObject;
Типы скалярных массивов
Для каждого встроенного типа данных, который может быть в массиве, существует тип Python. Большинство из них — это простые оболочки вокруг соответствующего типа данных в C. Имена типов в C — Py{TYPE}ArrType_Type , где {TYPE} может быть
Bool, Byte, Short, Int, Long, LongLong, UByte, UShort, UInt, ULong, ULongLong, Half, Float, Double, LongDouble, CFloat, CDouble, CLongDouble, String, Unicode, Void и Object.
Эти имена типов являются частью C-API и, следовательно, могут быть созданы в расширениях на C. Также есть PyIntpArrType_Type и PyUIntpArrType_Type, которые являются простыми заменами одного из целочисленных типов, которые могут хранить указатель на платформе. Структура этих скалярных объектов не раскрывается для кода C. Функция PyArray_ScalarAsCtype (..) может быть использована для извлечения значения типа C из скаляра массива, а функция PyArray_Scalar (…) — для создания скаляра массива из значения C.
Другие структуры C
Несколько новых структур C оказались полезными при разработке NumPy. Эти структуры C используются, по крайней мере, в одном вызове C-API и поэтому документированы здесь. Основная причина определения этих структур — упрощение использования Python ParseTuple C-API для преобразования объектов Python в полезные объекты C.
PyArray_Dims
- typePyArray_Dims
-
Эта структура очень полезна при интерпретации информации о форме и/или шагах. Структура:
typedef struct { npy_intp *ptr; int len; } PyArray_Dims;Члены этой структуры:
- npy_intp*ptr
-
Указатель на список целых чисел (
npy_intp), которые обычно представляют форму массива или шаги массива.
- intlen
-
Длина списка целых чисел. Предполагается, что доступ к ptr[0] до ptr[len-1] безопасен.
- npy_intp*ptr
PyArray_Chunk
- typePyArray_Chunk
-
Это эквивалентно структуре объекта буфера в Python до члена ptr. На 32-битных платформах (т.е., если
NPY_SIZEOF_INT==NPY_SIZEOF_INTP), член len также соответствует эквивалентному члену объекта буфера. Он полезен для представления общего сегмента памяти.typedef struct { PyObject_HEAD PyObject *base; void *ptr; npy_intp len; int flags; } PyArray_Chunk;Члены:
- PyObject*base
-
Объект Python, из которого берётся этот сегмент памяти. Необходим для правильного учёта памяти.
- void*ptr
-
Указатель на начало сегмента памяти.
- npy_intplen
-
Длина сегмента в байтах.
- intflags
-
Любые флаги данных (например,
NPY_ARRAY_WRITEABLE), которые следует использовать для интерпретации памяти.
- PyObject*base
PyArrayInterface
См. также
- typePyArrayInterface
-
Структура
PyArrayInterfaceопределена для того, чтобы NumPy и другие модули расширений могли использовать протокол быстрого интерфейса массивов. Метод__array_struct__объекта, поддерживающего протокол быстрого интерфейса массивов, должен возвращатьPyCapsule, содержащий указатель на структуруPyArrayInterfaceс соответствующими деталями массива. После создания нового массива атрибут должен бытьDECREF'd, что освободит структуруPyArrayInterface. Не забудьтеINCREFобъект (чьё значение атрибута__array_struct__было получено) и укажите, что базовый член новогоPyArrayObjectссылается на этот же объект. Таким образом, память для массива будет управляться правильно.typedef struct { int two; int nd; char typekind; int itemsize; int flags; npy_intp *shape; npy_intp *strides; void *data; PyObject *descr; } PyArrayInterface;- inttwo
-
целое число 2 в качестве проверки.
- intnd
-
число измерений в массиве.
- chartypekind
-
Символ, указывающий тип массива в соответствии с соглашениями типов: ‘t’ -> битовое поле, ‘b’ -> логическое, ‘i’ -> целое со знаком, ‘u’ -> целое без знака, ‘f’ -> с плавающей точкой, ‘c’ -> комплексное с плавающей точкой, ‘O’ -> объект, ‘S’ -> (байтовый) строка, ‘U’ -> юникод, ‘V’ -> пусто.
- intitemsize
-
Количество байтов, необходимое для каждого элемента в массиве.
- intflags
-
Любые биты
NPY_ARRAY_C_CONTIGUOUS(1),NPY_ARRAY_F_CONTIGUOUS(2),NPY_ARRAY_ALIGNED(0x100),NPY_ARRAY_NOTSWAPPED(0x200) илиNPY_ARRAY_WRITEABLE(0x400) для указания информации о данных. ФлагиNPY_ARRAY_ALIGNED,NPY_ARRAY_C_CONTIGUOUSиNPY_ARRAY_F_CONTIGUOUSфактически могут быть определены по другим параметрам. ФлагNPY_ARR_HAS_DESCR(0x800) также может быть установлен для указания объектам, потребляющим интерфейс массива версии 3, что член descr структуры присутствует (он будет проигнорирован объектами, потребляющими интерфейс массива версии 2).
- npy_intp*shape
-
Массив, содержащий размер массива в каждом измерении.
- npy_intp*strides
-
Массив, содержащий количество байтов, которые нужно переместить, чтобы перейти к следующему элементу в каждом измерении.
- void*data
-
Указатель на первый элемент массива.
- PyObject*descr
-
Объект Python, описывающий тип данных более подробно (такой же, как ключ descr в
__array_interface__). Этот член может бытьNULLесли typekind и itemsize предоставляют достаточно информации. Этот член также игнорируется, если в флагеNPY_ARR_HAS_DESCRустановлен флаг flags.
- inttwo
Внутренние структуры
Внутренне код использует дополнительные объекты Python, главным образом для управления памятью. Эти типы не доступны напрямую из Python и не представлены в C-API. Они включены здесь только для полноты и помощи в понимании кода.
- typePyUFuncLoopObject
-
Свободная оболочка для C-структуры, содержащей информацию, необходимую для циклов. Это полезно, если вы пытаетесь понять код циклов ufunc.
PyUFuncLoopObject— связанная C-структура. Она определена в заголовочном файлеufuncobject.h.
- typePyUFuncReduceObject
-
Свободная оболочка для C-структуры, содержащей информацию, необходимую для методов reduce-подобных ufunc. Это полезно, если вы пытаетесь понять код reduce, accumulate и reduce-at.
PyUFuncReduceObject— связанная C-структура. Она определена в заголовочном файлеufuncobject.h.
- typePyUFunc_Loop1d
-
Простой связанный список C-структур, содержащих информацию, необходимую для определения одномерного цикла для ufunc для каждой определенной сигнатуры пользовательского типа данных.
- PyTypeObjectPyArrayMapIter_Type
-
Обработка расширенных индексов выполняется с помощью этого типа Python. Это просто свободная оболочка вокруг C-структуры, содержащей переменные, необходимые для индексации массивов с расширенными индексами. Связанная C-структура,
PyArrayMapIterObject, полезна, если вы пытаетесь понять код отображения расширенных индексов. Она определена в заголовочном файлеarrayobject.hЭтот тип не доступен из Python и может быть заменён C-структурой. В качестве типа Python он использует управление памятью с подсчётом ссылок.
© 2005–2022 NumPy Developers
Licensed under the 3-clause BSD License.
https://numpy.org/doc/1.21/reference/c-api/types-and-structures.html