Spec-Zone.ru › NumPy 1.14

Типы Python и C-структуры

В коде C определены несколько новых типов. Большинство из них доступны из Python, но некоторые не экспонируются из-за ограниченного использования. Каждый новый тип Python имеет связанную PyObject * структуру с внутренней структурой, которая включает указатель на «таблицу методов», определяющую, как новое объект ведет себя в Python. Когда вы получаете объект Python в код C, вы всегда получаете указатель на PyObject структуру. Поскольку PyObject структура очень общая и определяет только PyObject_HEAD, сама по себе она не очень интересна. Однако разные объекты содержат больше деталей после PyObject_HEAD (но вы должны выполнить приведение к правильному типу, чтобы получить к ним доступ — или использовать функции-обработчики или макросы).

Определенные новые типы Python

Типы Python — функциональный эквивалент классов в Python в C. Создав новый тип Python, вы делаете доступным новый объект для Python. Объект ndarray является примером нового типа, определенного в C. Новые типы определяются в C двумя основными шагами:

  1. создание C-структуры (обычно с именем Py{Name}Object), которая бинарно совместима со структурой PyObject , но содержит дополнительную информацию, необходимую для данного конкретного объекта;
  2. заполнение таблицы 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

PyArrayObject C-структура содержит всю необходимую информацию для массива. Все экземпляры 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 \geq 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

Массив nargs \times ntypes 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

N-1 где N — число измерений в базовом массиве.

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

PyArrayMultiIter_Type

Этот тип предоставляет итератор, который обобщает концепцию вещания. Он позволяет N массивам быть совместимыми при вещании, таким образом, цикл будет проходить в стиле 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} может быть

Bool, Byte, Short, Int, Long, LongLong, UByte, UShort, UInt, ULong, ULongLong, Half, Float, Double, LongDouble, CFloat, CDouble, CLongDouble, String, Unicode, Void и Object.

Эти имена типов являются частью C-API и могут, следовательно, создаваться в расширенном коде C. Также есть PyIntpArrType_Type и PyUIntpArrType_Type, которые представляют собой простые замены одного из целочисленных типов, способных хранить указатель на платформе. Структура этих скалярных объектов не доступна для кода C. Функция PyArray_ScalarAsCtype (..) может быть использована для извлечения значения типа C из скаляра массива, а функция PyArray_Scalar (…) может быть использована для создания скаляра массива из значения C.

Другие структуры C

Несколько новых структур C оказались полезными при разработке NumPy. Эти структуры C используются как минимум в одном вызове C-API и поэтому документированы здесь. Основная причина определения этих структур — упрощение использования Python ParseTuple C-API для преобразования из Python-объектов в полезные C-объекты.

PyArray_Dims

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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API