Типы 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 -
C-структура
PyArrayObjectсодержит всю необходимую информацию для массива. Все экземпляры 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’ — строка Unicode длиной 32 бита/символ, а ‘V’ — произвольный.
-
char PyArray_Descr.type -
Традиционный символьный код, указывающий тип данных.
-
char PyArray_Descr.byteorder -
Символ, указывающий порядок байтов: ‘>’ (большая эндианность), ‘<’ (малая эндианность), ‘=’ (родная), ‘|’ (неважно, игнорировать). Все встроенные типы данных имеют порядок байтов ‘=’.
-
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 из скаляра массива используйте
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 -
Число, предоставляющее информацию об выравнивании для этого типа данных. В частности, оно показывает, как далеко от начала двумерной структуры (первый элемент которой является
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 и перестановки байтов, если указано. Значение 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* 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 (необходим для массивов переменной длины). Возвращает 0 при успешном выполнении или -1 при ошибке. Требуется корректный массив.
-
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на 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, включая интерфейсы tp_as_number, tp_as_sequence, tp_as_mapping и tp_as_buffer. Также используется сравнение rich comparison (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. Это очень простой тип, реализующий только базовые методы получения атрибутов, вывода и вызова, позволяющие этим объектам действовать как функциям. Основная идея 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используется, если extra_data не нужен. Несколько вызовов 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 для хранения места для членов types, data и name.
-
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 -
Когда атрибут
flagsизвлекается из 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-подобных ufunc. Это полезно, если вы пытаетесь понять код reduce, accumulate и reduce-at.
PyUFuncReduceObject— соответствующая C-структура. Она определена в заголовкеufuncobject.h.
-
PyUFunc_Loop1d -
Простой связанный список C-структур, содержащих информацию, необходимую для определения одномерного цикла для ufunc для каждой определенной подписи типа пользовательского данных.
-
PyArrayMapIter_Type -
Расширенная индексация обрабатывается с помощью этого типа Python. Это просто слабая оболочка вокруг C-структуры, содержащей переменные, необходимые для расширенной индексации массивов. Соответствующая C-структура,
PyArrayMapIterObject, полезна, если вы пытаетесь понять код сопоставления с расширенным индексом. Она определена в заголовкеarrayobject.h. Этот тип не отображается в Python и может быть заменен C-структурой. Как тип Python, он использует управление памятью с подсчетом ссылок.
© 2005–2019 NumPy Developers
Licensed under the 3-clause BSD License.
https://docs.scipy.org/doc/numpy-1.15.4/reference/c-api.types-and-structures.html