Типы 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 -
Структура
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, то этот массив является рабочей копией «неправильного» массива. Как только этот массив будет удалён, массив, на который указывает 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_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 -
Символ, указывающий порядок байтов: ‘>’ (большая эндианность), ‘<’ (малая эндианность), ‘=’ (родная), ‘|’ (неважно, игнорировать). Все встроенные типы данных имеют порядок байтов ‘=’.
-
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) -
Указатель на функцию, которая возвращает 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или одномерный массив, содержащий данные (если это необходимо для определения типа скаляра). Возвращаемое значение должно быть типаNPY_SCALARKIND.
-
int **cancastscalarkindto -
Либо
NULL, либо массив указателейNPY_NSCALARKINDS. Эти указатели должны быть либоNULL, либо указателем на массив целых чисел (завершённыйNPY_NOTYPE), указывающим типы данных, к которым скаляр этого типа данных указанного вида может быть безопасно преобразован (обычно это означает без потери точности).
-
int *cancastto -
Либо
NULL, либо массив целых чисел (завершённыйNPY_NOTYPE), указывающий типы данных, к которым этот тип данных может быть безопасно преобразован (обычно это означает без потери точности).
-
void fastclip(void *in, npy_intp n_in, void *min, void *max, void *out) -
Функция, которая считывает
n_inэлементов изin, и записывает вoutсчитанное значение, если оно находится в пределах, заданных указателямиminиmax, или соответствующим пределом, если оно за пределами. Сегменты памяти должны быть непрерывными и выровненными, и либоmin, либоmaxможет бытьNULL, но не оба.
-
-
void fastputmask(void *in, void *mask, npy_intp n_in, void *values, npy_intp nv) -
Функция, которая принимает указатель
inна массивn_inэлементов, указательmaskна массивn_inбулевых значений и указательvalsна массивnvэлементов. Элементы изvalsкопируются вinтам, где значение вmaskне равно нулю, с тилированиемvalsпри необходимости, еслиnv < n_in. Все массивы должны быть непрерывными и корректно обработанными.
-
void fasttake(void *dest, void *src, npy_intp *indarray, npy_intp nindarray, npy_intp n_outer, npy_intp m_middle, npy_intp nelem, NPY_CLIPMODE clipmode) -
Функция, которая принимает указатель
srcна непрерывный, корректно обработанный сегмент, интерпретируемый как 3-мерный массив формы(n_outer, nindarray, nelem), указательindarrayна непрерывный, корректно обработанный сегментm_middleцелочисленных индексов и указательdestна непрерывный, корректно обработанный сегмент, интерпретируемый как 3-мерный массив формы(n_outer, m_middle, nelem). Индексы вindarrayиспользуются для индексированияsrcпо второму измерению и копирования соответствующих фрагментов элементовnelemвdest.clipmode(который может принимать значенияNPY_RAISE,NPY_WRAPилиNPY_CLIP) определяет, как будут обрабатываться индексы, меньшие 0 или большие, чемnindarray.
-
int argmin(void* data, npy_intp n, npy_intp* min_ind, void* arr) -
Указатель на функцию, которая возвращает индекс наименьшего из
nэлементов вarr, начиная с элемента, на который указываетdata. Эта функция требует, чтобы сегмент памяти был непрерывным и корректно обработанным. Возвращаемое значение всегда равно 0. Индекс наименьшего элемента возвращается вmin_ind.
-
Тип PyArray_Type реализует многие функции объектов Python, включая интерфейсы 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используется, если 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 для хранения места для членов типа, данных и имени.
-
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-структуры
В процессе разработки NumPy было обнаружено несколько полезных C-структур. Эти 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-структур, содержащий информацию, необходимую для определения 1-мерного цикла для ufunc для каждой определённой подписи пользовательского типа данных.
-
PyArrayMapIter_Type -
Расширенный индексирование обрабатывается этим типом Python. Это просто упрощенная оболочка вокруг C-структуры, содержащей переменные, необходимые для расширенного индексирования массивов. Соответствующая C-структура,
PyArrayMapIterObject, полезна, если вы пытаетесь понять код отображения расширенного индекса. Она определена в заголовкеarrayobject.h. Этот тип не представлен в Python и может быть заменён C-структурой. Как тип Python, он использует управление памятью с подсчётом ссылок.
© 2008–2017 NumPy Developers
Licensed under the NumPy License.
https://docs.scipy.org/doc/numpy-1.13.0/reference/c-api.types-and-structures.html