Типы 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-битный/символьный строка Unicode, а ‘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 -
Указывает, что память для этого типа данных должна быть инициализирована (обнулена) при создании.
-
NPY_NEEDS_PYAPI -
Указывает, что этому типу данных требуется Python C-API при доступе (поэтому не отпускайте GIL, если доступ к массиву потребуется).
-
NPY_USE_GETITEM -
При доступе к массиву используйте указатель функции
f->getitemвместо стандартного преобразования в скаляр массива. Нужно использовать, если вы не определяете скаляр массива для сопровождения типа данных.
-
NPY_USE_SETITEM -
При создании одномерного массива из скаляра массива используйте
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; PyArray_FastPutmaskFunc *fastputmask; PyArray_FastTakeFunc *fasttake; 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друг на друга, складывает их и помещает результат в элемент, на который указываетopизarrНачало двух последовательностей указываетсяip1иip2Соответственно, для перехода к следующему элементу в каждой последовательности требуется переход наis1иis2байтов. Эта функция требует вежливой (хотя и не обязательно непрерывной) памяти.
-
int scanfunc(FILE* fd, void* ip, void* arr) -
Указатель на функцию, которая выполняет сканирование (в стиле scanf) одного элемента соответствующего типа из дескриптора файла
fdв память массива, на которую указываетip. Массив предполагается вежливым. Последний аргументarr— массив, в который выполняется сканирование. Возвращает количество успешно присвоенных аргументов (может быть ноль в случае ошибки соответствия, произошедшей до присвоения первого аргумента) или EOF, если возникает ошибка ввода до присвоения первого аргумента. Эта функция должна вызываться без удержания Python GIL и должна захватывать его для обработки ошибок.
-
int fromstr(char* str, void* ip, char** endptr, void* arr) -
Указатель на функцию, которая преобразует строку, на которую указывает
str, в один элемент соответствующего типа и помещает его в местоположение памяти, на которое указываетip. После завершения преобразования*endptrуказывает на остальную часть строки. Последний аргументarr— массив, в который указывает ip (необходим для массивов с переменным размером). Возвращает 0 при успехе или -1 при ошибке. Требуется вежливый массив. Эта функция должна вызываться без удержания Python GIL и должна захватывать его для обработки ошибок.
-
Bool nonzero(void* data, void* arr) -
Указатель на функцию, которая возвращает ИСТИНА, если элемент
arr, на который указываетdata, не равен нулю. Эта функция может обрабатывать массивы с нарушением «вежливости».
-
void fill(void* data, npy_intp length, void* arr) -
Указатель на функцию, которая заполняет непрерывный массив заданной длины данными. Первые два элемента массива должны быть уже заполнены. На основе этих двух значений будет вычислен дельта, а значения с элемента 3 до конца будут вычислены путем последовательного добавления этого вычисленного дельта. Буфер данных должен быть вежливым.
-
void fillwithscalar(void* buffer, npy_intp length, void* value, void* arr) -
Указатель на функцию, которая заполняет непрерывный
bufferзаданногоlengthодним скалярнымvalue, адрес которого задан. Последний аргумент — массив, необходимый для получения размера элемента для массивов переменной длины.
-
int sort(void* start, npy_intp length, void* arr) -
Массив указателей на функции определённых алгоритмов сортировки. Конкретный алгоритм сортировки получается с использованием ключа (до сих пор определены
NPY_QUICKSORT,NPY_HEAPSORTиNPY_MERGESORT). Эти сортировки выполняются на месте, предполагая непрерывные и выровненные данные.
-
int argsort(void* start, npy_intp* result, npy_intp length, void *arr) -
Массив указателей на функции сортировки для этого типа данных. Доступны те же алгоритмы сортировки, что и для sort. Индексы, которые приводят к сортировке, возвращаются в
result(который должен быть инициализирован индексами от 0 доlength-1включительно).
-
PyObject *castdict -
Либо
NULL, либо словарь, содержащий функции низкоуровневого преобразования для пользовательских типов данных. Каждая функция обернута вPyCObject *и проиндексирована номером типа данных.
-
NPY_SCALARKIND scalarkind(PyArrayObject* arr) -
Функция для определения того, как должны интерпретироваться скаляры этого типа. Аргумент —
NULLили одномерный массив, содержащий данные (если это необходимо для определения типа скаляра). Значение возврата должно быть типа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) -
Функция, которая считывает
n_inэлементов изin, и записывает вoutпрочитанное значение, если оно находится в пределах, указанныхminиmax, или соответствующего предела, если оно находится вне. Сегменты памяти должны быть непрерывными и вежливыми, и либоminилиmaxмогут бытьNULL, но не оба.
-
-
void fastputmask(void *in, void *mask, npy_intp n_in, void *values, npy_intp nv) -
Функция, принимающая указатель
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) -
Функция, принимающая указатель
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.
-
int argmin(void* data, npy_intp n, npy_intp* min_ind, void* arr) -
Указатель на функцию, которая извлекает индекс наименьшего из
nэлементов вarr, начиная с элемента, на который указываетdata. Эта функция требует, чтобы сегмент памяти был непрерывным и корректным. Возвращаемое значение всегда 0. Индекс наименьшего элемента возвращается вmin_ind.
-
Тип PyArray_Type реализует многие функции типа Python objects, включая интерфейсы tp_as_number, tp_as_sequence, tp_as_mapping и tp_as_buffer. Также используется rich comparison вместе с поиском атрибутов нового стиля для членов (tp_members) и свойств (tp_getset). Тип PyArray_Type также может быть подтипизирован.
Подсказка
Методы tp_as_number используют общий подход для вызова любой функции, которая была зарегистрирована для обработки операции. При импорте _multiarray_umath module, он устанавливает числовые операции для всех массивов на соответствующие ufuncs. Этот выбор можно изменить с помощью PyUFunc_ReplaceLoopBySignature. Методы tp_str и tp_repr также могут быть изменены с помощью PyArray_SetStringFunction.
Тип PyUFunc и объект PyUFuncObject
-
PyUFunc_Type -
Объект ufunc реализуется с помощью создания
PyUFunc_Type. Это очень простой тип, который реализует только базовое поведение getattribute, поведение вывода на печать и имеет поведение вызова, которое позволяет этим объектам действовать как функциям. Основная идея ufunc заключается в хранении ссылки на быстрые одномерные (векторные) циклы для каждого типа данных, поддерживающего операцию. Эти одномерные циклы имеют одинаковую сигнатуру и являются ключевыми для создания нового ufunc. Они вызываются общим кодом цикла по мере необходимости для реализации N-мерной функции. Также определены некоторые общие 1-мерные циклы для плавающих и комплексных плавающих массивов, которые позволяют определить 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 для UFuncs — это просто 1-мерные векторизованные циклы, которые используют эти дополнительные данные для получения указателя на фактическую функцию для вызова.
-
int PyUFuncObject.ntypes -
Количество поддерживаемых типов данных для ufunc. Это число задаёт, сколько различных 1-мерных циклов (для встроенных типов данных) доступно.
-
int PyUFuncObject.reserved1 -
Не используется.
-
char *PyUFuncObject.name -
Строковое имя ufunc. Оно используется динамически для построения атрибута __doc__ ufuncs.
-
char *PyUFuncObject.types -
Массив
8-битных номеров типов, содержащий сигнатуру типа для функции для каждого из поддерживаемых (встроенных) типов данных. Для каждой из ntypes функций соответствующий набор чисел типа в этом массиве показывает, как аргумент args должен интерпретироваться в 1-мерном векторизованном цикле. Эти номера типов не обязательно должны быть одного типа, и поддерживаются ufuncs смешанных типов.
-
char *PyUFuncObject.doc -
Документация для ufunc. Не должна содержать сигнатуру функции, так как она генерируется динамически при получении __doc__.
-
void *PyUFuncObject.ptr -
Любая динамически выделенная память. В настоящее время используется для динамически созданных ufuncs из python-функций для хранения места для членов types, data и name.
-
PyObject *PyUFuncObject.obj -
Для ufuncs, динамически созданных из python-функций, этот член содержит ссылку на базовую python-функцию.
-
PyObject *PyUFuncObject.userloops -
Словарь пользовательских 1-мерных векторизованных циклов (хранящихся как указатели CObject) для пользовательских типов. Пользователь может зарегистрировать цикл для любого пользовательского типа. Он извлекается по номеру типа. Номера пользовательских типов всегда больше
NPY_USERDEF.
-
int PyUFuncObject.core_enabled -
0 для скалярных ufuncs; 1 для обобщённых ufuncs
-
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 -
Функция, которая разрешает типы и заполняет массив dtypes для входных и выходных значений
-
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 -
Это объект итератора, который упрощает итерацию по N-мерному массиву. Он возвращается атрибутом flat массива ndarray. Он также широко используется во внутреннем коде для итерации по N-мерному массиву. Реализован интерфейс 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 -
N-мерный индекс в массиве.
-
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 -
Этот флаг равен true, если базовый массив
NPY_ARRAY_C_CONTIGUOUS. Используется для упрощения расчётов, когда это возможно.
-
Более подробное объяснение использования итератора массива на уровне C приведено в следующих разделах. Обычно вам не нужно заботиться о внутренней структуре объекта-итератора и взаимодействовать с ним только с помощью макросов PyArray_ITER_NEXT (it), PyArray_ITER_GOTO (it, dest) или PyArray_ITER_GOTO1D (it, index). Все эти макросы требуют в качестве аргумента it объект PyArrayIterObject *.
PyArrayMultiIter_Type и PyArrayMultiIterObject
-
PyArrayMultiIter_Type -
Этот тип предоставляет итератор, который обобщает понятие вещания. Он позволяет
массивам быть объединёнными по правилу вещания, чтобы цикл выполнялся в стиле C — непрерывно по объединённому массиву. Соответствующая C-структура —
PyArrayMultiIterObject, расположение памяти которой должно начинаться с любого объекта obj, переданного в функциюPyArray_Broadcast(obj). Вещание выполняется путём изменения итераторов массивов, таким образом, чтобы каждый итератор представлял собой вещаемую форму и размер, но его шаги изменяются для использования правильного элемента из массива на каждой итерации.
-
PyArrayMultiIterObject -
typedef struct { PyObject_HEAD int numiter; npy_intp size; npy_intp index; int nd; npy_intp dimensions[NPY_MAXDIMS]; PyArrayIterObject *iters[NPY_MAXDIMS]; } PyArrayMultiIterObject;-
int 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), которые должны использоваться для интерпретации памяти.
-
PyArrayInterface
См. также
-
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 для ufuncs. Это полезно, если вы пытаетесь понять код reduce, accumulate и reduce-at.
PyUFuncReduceObject— связанная C-структура. Она определена в заголовкеufuncobject.h.
-
PyUFunc_Loop1d -
Простой связанный список C-структур, содержащих информацию, необходимую для определения одномерного цикла для 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.18/reference/c-api/types-and-structures.html