Типы 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 — это тип описателя типа данных, экземпляры которого описывают данные.
PyArray_Type и PyArrayObject
-
PyArray_Type -
Тип Python для ndarray —
PyArray_Type. В C каждый ndarray — это указатель на структуруPyArrayObject. Член ob_type этой структуры содержит указатель на типPyArray_Type.
-
PyArrayObject -
C-структура
PyArrayObjectсодержит всю необходимую информацию для массива. Все экземпляры ndarray (и его подклассов) будут иметь эту структуру. Для обеспечения обратной совместимости члены этой структуры обычно должны извлекаться с помощью предоставленных макросов. Если вам нужно более короткое имя, то вы можете использоватьNPY_AO(устаревший), который определён как эквивалентныйPyArrayObject. Прямой доступ к полям структуры устарел. Используйте вместо этого форматPyArray_*(arr).typedef struct PyArrayObject { PyObject_HEAD char *data; int nd; npy_intp *dimensions; npy_intp *strides; PyObject *base; PyArray_Descr *descr; int flags; PyObject *weakreflist; } PyArrayObject;
-
PyArrayObject.PyObject_HEAD -
Это необходимо для всех объектов Python. Он состоит (по крайней мере) из члена счётчика ссылок (
ob_refcnt) и указателя на тип объекта (ob_type). (Другие элементы могут присутствовать, если Python был скомпилирован со специальными опциями, см. Include/object.h в дереве исходных текстов Python для получения дополнительной информации). Член ob_type указывает на объект типа Python.
-
char *PyArrayObject.data -
Доступно через
PyArray_DATA, этот член данных является указателем на первый элемент массива. Этот указатель можно (и обычно нужно) преобразовать в тип данных массива.
-
int PyArrayObject.nd -
Целое число, определяющее количество измерений для этого массива. Когда nd равно 0, массив иногда называется массивом ранга 0. Такие массивы имеют неопределённые размеры и шаги и не могут быть обработаны. Макрос
PyArray_NDIM, определённый вndarraytypes.h, указывает на этот член данных.NPY_MAXDIMS— это максимальное количество измерений для любого массива.
-
npy_intp PyArrayObject.dimensions -
Массив целых чисел, предоставляющий форму в каждом измерении, пока nd
1. Целое число всегда достаточно велико для хранения указателя на платформе, поэтому размер измерения ограничен только объёмом памяти.
PyArray_DIMS— макрос, связанный с этим членом данных.
-
npy_intp *PyArrayObject.strides -
Массив целых чисел, предоставляющий для каждого измерения количество байтов, которое необходимо пропустить, чтобы получить следующий элемент в этом измерении. Связан с макросом
PyArray_STRIDES.
-
PyObject *PyArrayObject.base -
На который указывает
PyArray_BASE, этот член используется для хранения указателя на другой объект Python, связанный с этим массивом. Существует два варианта использования:- Если этот массив не владеет собственной памятью, то base указывает на объект Python, который им владеет (возможно, другой объект массива)
- Если для этого массива установлен флаг (устаревший)
NPY_ARRAY_UPDATEIFCOPYилиNPY_ARRAY_WRITEBACKIFCOPY, то этот массив является рабочей копией «неправильного» массива.
При вызове
PyArray_ResolveWritebackIfCopy, массив, на который указывает base, будет обновлён содержимым этого массива.
-
PyArray_Descr *PyArrayObject.descr -
Указатель на объект-описатель типа данных (см. ниже). Объект-описатель типа данных — это экземпляр нового встроенного типа, который позволяет генерически описывать память. Для каждого поддерживаемого типа данных существует структура описателя. Эта структура описателя содержит полезную информацию о типе, а также указатель на таблицу указателей на функции для реализации определённой функциональности. Как следует из названия, она связана с макросом
PyArray_DESCR.
-
int PyArrayObject.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 *PyArrayObject.weakreflist -
Этот член позволяет объектам массива иметь слабые ссылки (используя модуль weakref).
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 *PyArray_Descr.typeobj -
Указатель на тип объекта, который является соответствующим типом Python для элементов этого массива. Для встроенных типов он указывает на соответствующий скаляр массива. Для типов пользовательского определения он должен указывать на объект типа пользовательского определения. Этот объект типа может либо наследоваться от скаляров массива, либо нет. Если он не наследуется от скаляров массива, то флаги
NPY_USE_GETITEMиNPY_USE_SETITEMдолжны быть установлены в членеflags.
-
char PyArray_Descr.kind -
Код символа, указывающий вид массива (используя обозначение типа строки интерфейса массива). ‘b’ представляет булевы значения, ‘i’ — целые со знаком, ‘u’ — целые без знака, ‘f’ — числа с плавающей запятой, ‘c’ — комплексные числа с плавающей запятой, ‘S’ — 8-битовые нуль-терминированные байты, ‘U’ — 32-битные/символьные строки Юникода, а ‘V’ — произвольные.
-
char PyArray_Descr.type -
Традиционный код символа, указывающий тип данных.
-
char PyArray_Descr.byteorder -
Символ, указывающий порядок байтов: ‘>’ (большая эндианность), ‘<’ (малая эндианность), ‘=’ (родная), ‘|’ (неважно, игнорировать). Все встроенные типы данных имеют порядок байтов ‘=’.
-
char PyArray_Descr.flags -
Флаг типа данных, определяющий, демонстрирует ли тип данных поведение массива объектов. Каждый бит в этом члене является флагом, которые имеют названия:
-
NPY_ITEM_REFCOUNT -
Указывает, что элементы этого типа данных должны иметь счётчик ссылок (используя
Py_INCREFиPy_DECREF).
-
NPY_ITEM_HASOBJECT -
То же, что и
NPY_ITEM_REFCOUNT.
-
NPY_LIST_PICKLE -
Указывает, что массивы этого типа данных должны быть преобразованы в список перед сериализацией.
-
NPY_ITEM_IS_POINTER -
Указывает, что элемент является указателем на другие данные типа
-
NPY_NEEDS_INIT -
Указывает, что память для этого типа данных должна быть инициализирована (установлена в 0) при создании.
-
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_REFCOUNT|NPY_NEEDS_INIT|NPY_NEEDS_PYAPI).
-
PyDataType_FLAGCHK(PyArray_Descr *dtype, int flags) -
Возвращает true, если все заданные флаги установлены для объекта типа данных.
-
PyDataType_REFCHK(PyArray_Descr *dtype) -
Эквивалентно
PyDataType_FLAGCHK(dtype,NPY_ITEM_REFCOUNT).
-
-
int PyArray_Descr.type_num -
Число, которое однозначно идентифицирует тип данных. Для новых типов данных это число назначается при регистрации типа данных.
-
int PyArray_Descr.elsize -
Для типов данных, которые всегда имеют одинаковый размер (например, long), это хранит размер типа данных. Для гибких типов данных, где разные массивы могут иметь различный размер элемента, это должно быть 0.
-
int PyArray_Descr.alignment -
Число, предоставляющее информацию об выравнивании для этого типа данных. В частности, оно показывает, насколько далеко от начала структуры из 2-х элементов (первый элемент которого является
char), компилятор помещает элемент этого типа:offsetof(struct {char c; type v;}, v)
-
PyArray_ArrayDescr *PyArray_Descr.subarray -
Если это не
NULL, то этот описатель типа данных представляет собой массив C-стиля с другим описателем типа данных. Другими словами, каждый элемент, который описывает этот описатель, фактически является массивом некоторого другого базового описателя. Это наиболее полезно в качестве описателя типа данных для поля в другом описателе типа данных. Член fields должен бытьNULLесли этот неNULL(член fields базового описателя может быть неNULLоднако). СтруктураPyArray_ArrayDescrопределена с помощьюtypedef struct { PyArray_Descr *base; PyObject *shape; } PyArray_ArrayDescr;Элементы этой структуры:
-
PyArray_Descr *PyArray_ArrayDescr.base -
Объект-описатель типа базового типа.
-
PyObject *PyArray_ArrayDescr.shape -
Форма (всегда C-стиля непрерывный) подмассива в виде кортежа Python.
-
-
PyObject *PyArray_Descr.fields -
Если это не NULL, то этот описатель типа данных имеет поля, описанные в словаре Python, ключи которого являются именами (и также заголовками, если они указаны), а значения — кортежами, описывающими поля. Помните, что описатель типа данных всегда описывает фиксированный набор байтов. Поле — это именованная подобласть этого полного, фиксированного набора. Поле описывается кортежем, состоящим из другого описателя типа данных и смещения байтов. По желанию, кортеж может содержать заголовок, который обычно является строкой Python. Эти кортежи помещаются в этот словарь с ключом имени (и также заголовком, если он задан).
-
PyObject *PyArray_Descr.names -
Упорядоченный кортеж имён полей. Он равен NULL, если поля не определены.
-
PyArray_ArrFuncs *PyArray_Descr.f -
Указатель на структуру, содержащую функции, которые тип должен реализовать для внутренних функций. Эти функции — не то же самое, что универсальные функции (ufuncs), описанные позже. Их подписи могут произвольно изменяться.
-
PyObject *PyArray_Descr.metadata -
Метаданные об этом типе данных.
-
NpyAuxData *PyArray_Descr.c_metadata -
Метаданные, специфичные для реализации C конкретного типа данных. Добавлено для NumPy 1.7.0.
-
Npy_hash_t *PyArray_Descr.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 и инверсии байтов, если указано. Значение 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-длинные последовательности, складывает их и помещает результат в элемент, на который указываетarr. Начало двух последовательностей указывается параметрамиip1иip2. Для перехода к следующему элементу в каждой последовательности требуется переход наis1иis2байтов соответственно. Эта функция требует «вежливой» (хотя и не обязательно непрерывной) памяти.
-
int scanfunc(FILE* fd, void* ip, void* arr) -
Указатель на функцию, которая выполняет сканирование (в стиле scanf) одного элемента соответствующего типа из дескриптора файла
fdв память массива, на которую указываетip. Массив предполагается «вежливым». Последний аргументarr— массив, в который будет производиться сканирование. Возвращает количество успешно присвоенных аргументов (может быть нулем в случае неудачи сопоставления до присвоения первого аргумента) или EOF, если произошла ошибка ввода до присвоения первого аргумента. Эта функция должна вызываться без удержания Python GIL и должна захватывать его для сообщения об ошибках.
-
int fromstr(char* str, void* ip, char** endptr, void* arr) -
Указатель на функцию, которая преобразует строку, на которую указывает
str, в один элемент соответствующего типа и помещает его в ячейку памяти, на которую указываетip. После завершения преобразования*endptrуказывает на остальную часть строки. Последний аргументarr— массив, в который указывает ip (необходим для данных переменной длины).
-
Bool nonzero(void* data, void* arr) -
Указатель на функцию, которая возвращает TRUE, если элемент
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, либо словарь, содержащий функции преобразования низкого уровня для пользовательских типов данных. Каждая функция обернута вPyCObject *и имеет ключ — номер типа данных.
-
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на непрерывный, корректный сегмент C, интерпретируемый как трёхмерный массив формы(n_outer, nindarray, nelem), указательindarrayна непрерывный, корректный сегментm_middleцелочисленных индексов и указательdestна непрерывный, корректный сегмент C, интерпретируемый как трёхмерный массив формы(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, он устанавливает числовые операции для всех массивов в соответствующие ufunc. Этот выбор может быть изменён с помощью PyUFunc_ReplaceLoopBySignature. Методы tp_str и tp_repr также могут быть изменены с помощью PyArray_SetStringFunction.
PyUFunc_Type и PyUFuncObject
-
PyUFunc_Type -
Объект ufunc реализуется путём создания
PyUFunc_Type. Это очень простой тип, реализующий только базовые методы получения атрибутов, вывода в печать и поведение вызовов, позволяющее этим объектам действовать как функциям. Основная идея 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_intp *core_dim_flags; } PyUFuncObject;-
int PyUFuncObject.nin -
Количество входных аргументов.
-
int PyUFuncObject.nout -
Количество выходных аргументов.
-
int PyUFuncObject.nargs -
Общее количество аргументов (nin + nout). Оно должно быть меньше
NPY_MAXARGS.
-
int PyUFuncObject.identity -
Либо
PyUFunc_One,PyUFunc_Zero,PyUFunc_NoneилиPyUFunc_AllOnesдля указания тождества для данной операции. Используется только для вызова типа reduce для пустого массива.
-
void PyUFuncObject.functions(char** args, npy_intp* dims, npy_intp* steps, void* extradata) -
Массив указателей на функции — по одному для каждого типа данных, поддерживаемого ufunc. Это цикл векторных операций, который вызывается для реализации подлежащей функции dims [0] раз. Первый аргумент, args, — это массив из nargs указателей на данные. Сначала идут указатели на данные входных аргументов, а затем — указатели на данные выходных аргументов. Количество байтов, которое нужно пропустить, чтобы получить следующий элемент в последовательности, задается соответствующим элементом в массиве steps. Последний аргумент позволяет циклу получать дополнительную информацию. Это обычно используется для того, чтобы один общий цикл векторных операций мог использоваться для нескольких функций. В этом случае фактическая скалярная функция для вызова передаётся как extradata. Размер этого массива указателей на функции равен ntypes.
-
void **PyUFuncObject.data -
Дополнительные данные, которые нужно передать циклам 1-мерных векторов, или
NULLесли дополнительные данные не нужны. Этот массив C должен иметь тот же размер (т.е. ntypes), что и массив функций.NULLиспользуется, если дополнительные данные не нужны. Несколько вызовов C-API для UFunc представляют собой циклы 1-мерных векторов, которые используют эти дополнительные данные для получения указателя на фактическую вызываемую функцию.
-
int PyUFuncObject.ntypes -
Количество поддерживаемых типов данных для ufunc. Это число определяет, сколько доступно различных 1-мерных циклов (встроенных типов данных).
-
int PyUFuncObject.reserved1 -
Не используется.
-
char *PyUFuncObject.name -
Строковое имя ufunc. Используется динамически для построения атрибута __doc__ ufunc.
-
char *PyUFuncObject.types -
Массив
8-битовых номеров типов, содержащий подпись типа для функции для каждого из поддерживаемых (встроенных) типов данных. Для каждой из ntypes функций соответствующий набор номеров типов в этом массиве показывает, как аргумент args должен интерпретироваться в цикле 1-мерных векторов. Эти номера типов не обязательно должны быть одинаковыми, и поддерживаются ufuncs смешанных типов.
-
char *PyUFuncObject.doc -
Документация для ufunc. Не должна содержать подпись функции, так как она генерируется динамически при получении __doc__.
-
void *PyUFuncObject.ptr -
Любая динамически выделенная память. В настоящее время используется для динамических ufunc, созданных из Python-функции, для хранения места для членов типов, данных и имени.
-
PyObject *PyUFuncObject.obj -
Для ufunc, динамически созданных из Python-функций, этот член хранит ссылку на базовую Python-функцию.
-
PyObject *PyUFuncObject.userloops -
Словарь пользовательских 1-мерных циклов векторных операций (хранящихся как указатели CObject) для пользовательских типов. Пользователь может зарегистрировать цикл для любого пользовательского типа. Он извлекается по номеру типа. Номера пользовательских типов всегда больше, чем
NPY_USERDEF.
-
int PyUFuncObject.core_enabled -
0 для скалярных ufunc; 1 для обобщённых ufunc
-
int PyUFuncObject.core_num_dim_ix -
Количество различных имён измерений ядра в подписи
-
int *PyUFuncObject.core_num_dims -
Количество измерений ядра каждого аргумента
-
int *PyUFuncObject.core_dim_ixs -
Индексы измерений в уплощённой форме; индексы аргумента
kхранятся вcore_dim_ixs[core_offsets[k] : core_offsets[k] + core_numdims[k]]
-
int *PyUFuncObject.core_offsets -
Позиция первого измерения ядра каждого аргумента в
core_dim_ixs, эквивалентная cumsum(core_num_dims)
-
char *PyUFuncObject.core_signature -
Строка подписи ядра
-
PyUFunc_TypeResolutionFunc *PyUFuncObject.type_resolver -
Функция, которая разрешает типы и заполняет массив с типами данных для входных и выходных данных
-
PyUFunc_LegacyInnerLoopSelectionFunc *PyUFuncObject.legacy_inner_loop_selector -
Функция, которая возвращает внутренний цикл. Приставка «legacy» в названии происходит от того, что для NumPy 1.6 планировалась лучшая версия. Эта версия пока не реализована.
-
void *PyUFuncObject.reserved2 -
Для возможного будущего селектора цикла с другой подписью.
-
PyUFunc_MaskedInnerLoopSelectionFunc *PyUFuncObject.masked_inner_loop_selector -
Функция, возвращающая внутренний цикл для ufunc с масками
-
npy_uint32 PyUFuncObject.op_flags -
Переопределение значений флагов операнда по умолчанию для каждого операнда ufunc.
-
npy_uint32 PyUFuncObject.iter_flags -
Переопределение значений флагов nditer по умолчанию для ufunc.
Добавлен в версии API 0x0000000D
-
npy_intp *PyUFuncObject.core_dim_sizes -
Для каждого уникального измерения ядра, возможный замороженный размер, если
UFUNC_CORE_DIM_SIZE_INFERREDравно 0
-
npy_uint32 *PyUFuncObject.core_dim_flags -
Для каждого уникального измерения ядра, набор
UFUNC_CORE_DIM*флагов-
UFUNC_CORE_DIM_CAN_IGNOREесли имя измерения заканчивается на? -
UFUNC_CORE_DIM_SIZE_INFERREDесли размер измерения будет определён из операндов, а не из замороженной подписи
-
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; Bool contiguous; } PyArrayIterObject;-
int PyArrayIterObject.nd_m1 -
где
— количество измерений в базовом массиве.
-
npy_intp PyArrayIterObject.index -
Текущий одномерный индекс в массиве.
-
npy_intp PyArrayIterObject.size -
Полный размер базового массива.
-
npy_intp *PyArrayIterObject.coordinates -
Индекс в массиве с
измерениями.
-
npy_intp *PyArrayIterObject.dims_m1 -
Размер массива минус 1 по каждому измерению.
-
npy_intp *PyArrayIterObject.strides -
Шаги массива. Сколько байтов требуется для перехода к следующему элементу в каждом измерении.
-
npy_intp *PyArrayIterObject.backstrides -
Сколько байтов требуется для перехода от конца измерения к его началу. Обратите внимание, что
backstrides[k] == strides[k] * dims_m1[k], но хранится здесь для оптимизации.
-
npy_intp *PyArrayIterObject.factors -
Этот массив используется для вычисления N-мерного индекса из одномерного индекса. Он содержит необходимые произведения размерностей.
-
PyArrayObject *PyArrayIterObject.ao -
Указатель на базовый ndarray, для представления которого был создан этот итератор.
-
char *PyArrayIterObject.dataptr -
Этот член указывает на элемент в ndarray, соответствующий индексу.
-
Bool PyArrayIterObject.contiguous -
Флаг, истинный, если базовый массив является
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 PyArrayMultiIterObject.numiter -
Количество массивов, которые необходимо объединить до одной формы.
-
npy_intp PyArrayMultiIterObject.size -
Общий объединённый размер.
-
npy_intp PyArrayMultiIterObject.index -
Текущий (одномерный) индекс в объединённом результате.
-
int PyArrayMultiIterObject.nd -
Количество измерений в объединённом результате.
-
npy_intp *PyArrayMultiIterObject.dimensions -
Форма объединённого результата (используются только
ndслоты).
-
PyArrayIterObject **PyArrayMultiIterObject.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 -
При получении атрибута флагов из 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 и поэтому документированы здесь. Основная причина определения этих структур — упростить использование C-API Python ParseTuple для преобразования объектов Python в полезные объекты C.
PyArray_Dims
-
PyArray_Dims -
Эта структура очень полезна, когда предполагается интерпретация информации о форме и/или шагах. Структура:
typedef struct { npy_intp *ptr; int len; } PyArray_Dims;Члены этой структуры:
-
npy_intp *PyArray_Dims.ptr -
Указатель на список (
npy_intp) целых чисел, которые обычно представляют форму массива или шаги массива.
-
int PyArray_Dims.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 *PyArray_Chunk.base -
Объект Python, из которого происходит этот фрагмент памяти. Необходим для правильного учёта памяти.
-
void *PyArray_Chunk.ptr -
Указатель на начало сегмента памяти с одним сегментом.
-
npy_intp PyArray_Chunk.len -
Длина сегмента в байтах.
-
int PyArray_Chunk.flags -
Любые флаги данных (например,
NPY_ARRAY_WRITEABLE), которые должны использоваться для интерпретации памяти.
-
Интерфейс PyArray
См. также
-
PyArrayInterface -
Структура
PyArrayInterfaceопределена так, чтобы NumPy и другие модули расширения могли использовать протокол быстрого интерфейса массивов. Метод__array_struct__объекта, поддерживающего протокол быстрого интерфейса массивов, должен возвращатьPyCObject, который содержит указатель на структуруPyArrayInterfaceс соответствующими подробностями массива. После создания нового массива атрибут должен бытьDECREF’d, что освободит структуру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 PyArrayInterface.two -
целое число 2 в качестве проверки на корректность.
-
int PyArrayInterface.nd -
число измерений в массиве.
-
char PyArrayInterface.typekind -
Символ, указывающий, какой массив присутствует в соответствии с соглашением о типах строки: ‘t’ -> битовое поле, ‘b’ -> булево, ‘i’ -> целое со знаком, ‘u’ -> целое без знака, ‘f’ -> число с плавающей точкой, ‘c’ -> комплексное число с плавающей точкой, ‘O’ -> объект, ‘S’ -> (байтовая) строка, ‘U’ -> строка Юникод, ‘V’ -> пустое.
-
int PyArrayInterface.itemsize -
Количество байтов, необходимых для каждого элемента в массиве.
-
int PyArrayInterface.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 *PyArrayInterface.shape -
Массив, содержащий размер массива в каждом измерении.
-
npy_intp *PyArrayInterface.strides -
Массив, содержащий количество байтов, которые нужно пропустить, чтобы перейти к следующему элементу в каждом измерении.
-
void *PyArrayInterface.data -
Указатель на первый элемент массива.
-
PyObject *PyArrayInterface.descr -
Объект Python, описывающий тип данных более подробно (так же, как ключ descr в
__array_interface__). Это может бытьNULLесли typekind и itemsize предоставляют достаточно информации. Этот поле также игнорируется, если флаг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-структур, содержащих информацию, необходимую для определения цикла 1d для ufunc для каждой определенной сигнатуры пользовательского типа данных.
-
PyArrayMapIter_Type -
Обработка расширенного индексирования выполняется с помощью этого типа Python. Это просто упрощенная оболочка вокруг C-структуры, содержащей переменные, необходимые для индексирования массивов с расширенным индексом. Соответствующая C-структура,
PyArrayMapIterObject, полезна, если вы пытаетесь понять код отображения индексов с расширенным индексом. Она определена вarrayobject.hзаголовке. Этот тип не доступен в Python и может быть заменён C-структурой. В качестве типа Python он использует управление памятью с подсчётом ссылок.
© 2005–2020 NumPy Developers
Licensed under the 3-clause BSD License.
https://numpy.org/doc/1.19/reference/c-api/types-and-structures.html