Типы 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
-
PyArray_Type -
Тип Python ndarray —
PyArray_Type. В C каждый ndarray — указатель наPyArrayObjectструктуру. Член ob_type этой структуры содержит указатель на типPyArray_Type.
-
PyArrayObject -
PyArrayObjectC-структура содержит всю необходимую информацию для массива. Все экземпляры ndarray (и его подклассов) будут иметь эту структуру. Для обеспечения совместимости в будущем члены этих структур обычно должны обращаться к предоставленным макросам. Если вам нужно более короткое имя, вы можете использоватьNPY_AO, которое эквивалентноPyArrayObject.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;
-
char *PyArrayObject.data -
Указатель на первый элемент массива. Этот указатель можно (и обычно следует) переинтерпретировать как указатель на тип данных массива.
-
int PyArrayObject.nd -
Целое число, определяющее количество измерений для этого массива. Когда nd равно 0, массив иногда называется массивом ранга 0. Такие массивы имеют неопределённые размеры и шаги и недоступны.
NPY_MAXDIMS— это максимальное количество измерений для любого массива.
-
npy_intp PyArrayObject.dimensions -
Массив целых чисел, определяющий размерность в каждом измерении до тех пор, пока nd
1. Целое число всегда достаточно велико, чтобы вместить указатель на платформе, поэтому размер измерения ограничен только памятью.
-
npy_intp *PyArrayObject.strides -
Массив целых чисел, определяющий для каждого измерения количество байтов, которые необходимо пропустить, чтобы перейти к следующему элементу в этом измерении.
-
PyObject *PyArrayObject.base -
Этот член используется для хранения указателя на другой объект Python, связанный с этим массивом. Существуют два случая использования: 1) Если этот массив не владеет собственной памятью, то base указывает на объект Python, который владеет ею (возможно, другой объект массива), 2) Если у этого массива установлен (устаревший) флаг
NPY_ARRAY_UPDATEIFCOPYили :c:data:NPY_ARRAY_WRITEBACKIFCOPY`, то этот массив является рабочей копией «неправильного» массива. При вызовеPyArray_ResolveWritebackIfCopy, массив, на который указывает base, будет обновлён содержимым этого массива.
-
PyArray_Descr *PyArrayObject.descr -
Указатель на объект-описатель типа данных (см. ниже). Объект-описатель типа данных — это экземпляр нового встроенного типа, который позволяет генерически описывать память. Для каждого поддерживаемого типа данных существует структура описателя. Эта структура описателя содержит полезную информацию о типе, а также указатель на таблицу указателей на функции для реализации конкретных функций.
-
int PyArrayObject.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
-
PyArrayDescr_Type -
PyArrayDescr_Type— это встроенный тип объектов описателя типа данных, используемых для описания того, как интерпретировать байты, составляющие массив. Существует 21 статически определённый объектPyArray_Descrдля встроенных типов данных. Хотя они участвуют в подсчёте ссылок, их счётчик ссылок никогда не должен достигать нуля. Также поддерживается динамическая таблица пользовательских объектовPyArray_Descr. После «регистрации» объекта описателя типа данных его никогда не следует удалять. ФункцияPyArray_DescrFromType(…) может использоваться для извлечения объектаPyArray_Descrпо номеру типа (встроенному или пользовательскому).
-
PyArray_Descr -
Формат структуры
PyArray_Descr, лежащей в основеPyArrayDescr_Type, таков:typedef struct { PyObject_HEAD PyTypeObject *typeobj; char kind; char type; char byteorder; char unused; int flags; int type_num; int elsize; int alignment; PyArray_ArrayDescr *subarray; PyObject *fields; PyArray_ArrFuncs *f; } 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 -
Символ, указывающий порядок байтов: ‘>’ (big-endian), ‘<’ (little-endian), ‘=’ (родной), ‘|’ (нерелевантный, игнорировать). Все встроенные типы данных имеют порядок байтов ‘=’.
-
int PyArray_Descr.flags -
Флаги типа данных, определяющие, демонстрирует ли тип данных поведение массива объектов. Каждый бит в этом члене — флаг, который имеет названия:
-
NPY_ITEM_REFCOUNT
-
NPY_ITEM_HASOBJECT -
Указывает, что элементы этого типа данных должны быть учтены в счётчике ссылок (используя
Py_INCREFиPy_DECREF).
-
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-d из скаляра массива используйте
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-строкой. Эти кортежи помещаются в этот словарь с ключами по имени (и также заголовком, если он указан).
-
PyArray_ArrFuncs *PyArray_Descr.f -
Указатель на структуру, содержащую функции, которые тип должен реализовать для внутренних функций. Эти функции не являются теми же самыми, что универсальные функции (ufuncs), описанные позже. Их сигнатуры могут варьироваться произвольно.
-
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 и swap, если указано. Значение arr используется только для гибких (
NPY_STRING,NPY_UNICODEиNPY_VOID) массивов (и получено изarr->descr->elsize). Вторая функция копирует одно значение, а первая перебирает n значений с заданными шагами. Эти функции могут обрабатывать данные с неправильным расположением в src. Если src равно NULL, то копирование не выполняется. Если swap равно 0, то перестановка байтов не происходит. Предполагается, что dest и src не перекрываются. Если они перекрываются, то сначала используйтеmemmove(…), а затемcopyswap(n)сsrcсо значением NULL.
-
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* sep, void* arr) -
Указатель на функцию, которая сканирует (в стиле scanf) один элемент соответствующего типа из дескриптора файла
fdв память массива, на которую указываетip. Массив предполагается выровненным. Еслиsepне равно NULL, то также сканируется разделительная строка из файла перед возвратом. Последний аргументarr— массив, в который производится сканирование. Возвращается 0, если сканирование выполнено успешно. Отрицательное число указывает на ошибку: -1 означает, что конец файла достигнут до того, как была прочитана разделительная строка, -4 означает, что конец файла достигнут до того, как был прочитан элемент, а -3 означает, что элемент не удалось интерпретировать из строкового формата. Требуется выровненный массив.
-
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) -
Функция, которая считывает
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на непрерывный, корректный сегмент, интерпретируемый как трёхмерный массив формы(n_outer, nindarray, nelem), указательindarrayна непрерывный, корректный сегментm_middleцелочисленных индексов и указательdestна непрерывный, корректный сегмент, интерпретируемый как трёхмерный массив формы(n_outer, m_middle, nelem). Индексы вindarrayиспользуются для индексированияsrcпо второму измерению и копирования соответствующих фрагментовnelemэлементов вdest. Значениеclipmode(которое может принимать значенияNPY_RAISE,NPY_WRAPилиNPY_CLIP) определяет, как будут обрабатываться индексы, меньшие 0 или большиеnindarray.
-
int argmin(void* data, npy_intp n, npy_intp* min_ind, void* arr) -
Указатель на функцию, которая получает индекс наименьшего из
nэлементов вarr, начиная с элемента, на который указываетdata. Эта функция требует, чтобы сегмент памяти был непрерывным и корректным. Возвращаемое значение всегда равно 0. Индекс наименьшего элемента возвращается вmin_ind.
-
Тип PyArray_Type реализует многие функции Python-объектов, включая интерфейсы tp_as_number, tp_as_sequence, tp_as_mapping и tp_as_buffer. Также используется сравнение с помощью tp_richcompare, а также поиск атрибутов нового стиля для методов (tp_methods) и свойств (tp_getset). Тип PyArray_Type также может быть подтипизирован.
Подсказка
Методы tp_as_number используют общий подход для вызова функции, зарегистрированной для обработки операции. Функция PyNumeric_SetOps(..) может быть использована для регистрации функций для обработки конкретных математических операций (для всех массивов). При импорте модуля umath, числовые операции для всех массивов устанавливаются на соответствующие ufuncs. Методы tp_str и tp_repr также могут быть изменены с помощью PyString_SetStringFunction(…).
PyUFunc_Type
-
PyUFunc_Type -
Объект ufunc реализуется созданием
PyUFunc_Type. Это очень простой тип, который реализует только базовые поведение getattribute, печать и имеет поведение вызова, что позволяет этим объектам действовать как функции. Основная идея ufunc заключается в хранении ссылки на быстрые одномерные (векторные) циклы для каждого типа данных, который поддерживает операцию. Все эти одномерные циклы имеют одинаковый синтаксис и являются ключевыми для создания нового ufunc. Они вызываются общим кодом циклов как соответствующим образом для реализации N-мерной функции. Также определены некоторые общие одномерные циклы для плавающих и комплексных плавающих массивов, которые позволяют вам определить ufunc, используя одну скалярную функцию (например, atanh).
-
PyUFuncObject -
Ядром ufunc является
PyUFuncObject, который содержит всю необходимую информацию для вызова базовых C-кодовых циклов, выполняющих фактическую работу. Он имеет следующую структуру: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; npy_uint32 *op_flags; npy_uint32 *iter_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 -
Дополнительные данные, передаваемые одномерным векторным циклам или
NULLесли дополнительные данные не нужны. Этот массив C должен иметь тот же размер (т.е. ntypes), что и массив функций.NULLиспользуется, если дополнительные данные не нужны. Несколько вызовов C-API для UFuncs — это просто одномерные векторные циклы, которые используют эти дополнительные данные для получения указателя на фактическую вызываемую функцию.
-
int PyUFuncObject.ntypes -
Количество поддерживаемых типов данных для ufunc. Это число определяет, сколько доступно различных одномерных циклов (для встроенных типов данных).
-
char *PyUFuncObject.name -
Строковое имя для ufunc. Используется динамически для построения атрибута __doc__ ufuncs.
-
char *PyUFuncObject.types -
Массив
8-битных номеров типов, содержащий подпись типа для функции для каждого из поддерживаемых (встроенных) типов данных. Для каждой из ntypes функций соответствующий набор номеров типов в этом массиве показывает, как аргумент args должен интерпретироваться в одномерном векторном цикле. Эти номера типов не обязательно должны быть одинаковыми, и смешанные типы ufuncs поддерживаются.
-
char *PyUFuncObject.doc -
Документация для ufunc. Не должна содержать сигнатуру функции, так как она генерируется динамически при получении __doc__.
-
void *PyUFuncObject.ptr -
Любая динамически выделенная память. В настоящее время используется для динамически созданных ufuncs из python-функций для хранения места для членов типов, данных и имени.
-
PyObject *PyUFuncObject.obj -
Для ufuncs, динамически созданных из python-функций, этот член хранит ссылку на базовую Python-функцию.
-
PyObject *PyUFuncObject.userloops -
Словарь пользовательских одномерных векторных циклов (хранящихся как указатели CObject) для пользовательских типов. Пользователь может зарегистрировать цикл для любого пользовательского типа. Он извлекается по номеру типа. Номера пользовательских типов всегда больше, чем
NPY_USERDEF.
-
npy_uint32 PyUFuncObject.op_flags -
Переопределение стандартных флагов операндов для каждого операнда ufunc.
-
npy_uint32 PyUFuncObject.iter_flags -
Переопределение стандартных флагов nditer для ufunc.
-
PyArrayIter_Type
-
PyArrayIter_Type -
Это объект итератора, который упрощает циклы по N-мерному массиву. Это объект, возвращаемый из атрибута flat ndarray. Он также широко используется во внутренней реализации для циклов по N-мерному массиву. Реализован интерфейс tp_as_mapping, чтобы объект итератора можно было индексировать (используя одномерный индексирование), и несколько методов реализованы через таблицу 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 -
Этот флаг имеет значение True, если базовый массив является
NPY_ARRAY_C_CONTIGUOUS. Он используется для упрощения вычислений, когда это возможно.
-
Более подробное описание использования итератора массива на уровне C приведено в последующих разделах. Как правило, вам не нужно беспокоиться о внутренней структуре объекта итератора и взаимодействовать с ним с помощью макросов PyArray_ITER_NEXT (it), PyArray_ITER_GOTO (it, dest) или PyArray_ITER_GOTO1D (it, index). Все эти макросы требуют, чтобы аргумент it был PyArrayIterObject *.
PyArrayMultiIter_Type
-
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
-
PyArrayNeighborhoodIter_Type -
Объект-итератор, упрощающий цикл по N-мерному окрестному массиву.
-
PyArrayNeighborhoodIterObject -
Структура C, соответствующая объекту
PyArrayNeighborhoodIter_Type, — этоPyArrayNeighborhoodIterObject.
PyArrayFlags_Type
-
PyArrayFlags_Type -
При получении атрибута флагов из Python, создаётся специальный встроенный объект этого типа. Этот специальный тип упрощает работу с различными флагами, позволяя обращаться к ним как к атрибутам или как к элементам словаря, где ключами являются имена флагов.
Типы скалярных массивов
Для каждого из различных встроенных типов данных, которые могут присутствовать в массиве, существует тип Python. Большинство из них — простые оболочки вокруг соответствующего типа данных в C. Имена C для этих типов — Py{TYPE}ArrType_Type где {TYPE} может быть
Эти имена типов являются частью C-API и могут, следовательно, создаваться в расширенном коде C. Также есть PyIntpArrType_Type и PyUIntpArrType_Type, которые представляют собой простые замены одного из целочисленных типов, способных хранить указатель на платформе. Структура этих скалярных объектов не доступна для кода C. Функция PyArray_ScalarAsCtype (..) может быть использована для извлечения значения типа C из скаляра массива, а функция PyArray_Scalar (…) может быть использована для создания скаляра массива из значения C.
Другие структуры C
Несколько новых структур C оказались полезными при разработке NumPy. Эти структуры C используются как минимум в одном вызове C-API и поэтому документированы здесь. Основная причина определения этих структур — упрощение использования Python ParseTuple C-API для преобразования из Python-объектов в полезные C-объекты.
PyArray_Dims
-
PyArray_Dims -
Эта структура очень полезна, когда требуется интерпретировать информацию о форме и/или шагах. Структура выглядит следующим образом:
typedef struct { npy_intp *ptr; int len; } PyArray_Dims;Членами этой структуры являются
-
npy_intp *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–2019 NumPy Developers
Licensed under the 3-clause BSD License.
https://docs.scipy.org/doc/numpy-1.14.5/reference/c-api.types-and-structures.html