Интерфейс итератора массивов
Новая версия 1.6.
Итератор массивов
Итератор массивов объединяет многие ключевые функции ufuncs, позволяя коду пользователя поддерживать такие функции, как параметры вывода, сохранение компоновки памяти и буферизацию данных с неправильным выравниванием или типом, без необходимости сложных кодировок.
На этой странице документирован интерфейс итератора. Итератор называется NpyIter, а функции называются NpyIter_*.
Существует вводное руководство по итерации массивов, которое может быть полезным для тех, кто использует этот C API. Во многих случаях полезно сначала протестировать идеи, создав итератор в Python, прежде чем писать код итерации на C.
Пример простой итерации
Лучший способ ознакомиться с итератором — изучить его использование в самом коде NumPy. Например, вот немного изменённая версия кода для PyArray_CountNonzero, который считает количество ненулевых элементов в массиве.
npy_intp PyArray_CountNonzero(PyArrayObject* self)
{
/* Nonzero boolean function */
PyArray_NonzeroFunc* nonzero = PyArray_DESCR(self)->f->nonzero;
NpyIter* iter;
NpyIter_IterNextFunc *iternext;
char** dataptr;
npy_intp nonzero_count;
npy_intp* strideptr,* innersizeptr;
/* Handle zero-sized arrays specially */
if (PyArray_SIZE(self) == 0) {
return 0;
}
/*
* Create and use an iterator to count the nonzeros.
* flag NPY_ITER_READONLY
* - The array is never written to.
* flag NPY_ITER_EXTERNAL_LOOP
* - Inner loop is done outside the iterator for efficiency.
* flag NPY_ITER_NPY_ITER_REFS_OK
* - Reference types are acceptable.
* order NPY_KEEPORDER
* - Visit elements in memory order, regardless of strides.
* This is good for performance when the specific order
* elements are visited is unimportant.
* casting NPY_NO_CASTING
* - No casting is required for this operation.
*/
iter = NpyIter_New(self, NPY_ITER_READONLY|
NPY_ITER_EXTERNAL_LOOP|
NPY_ITER_REFS_OK,
NPY_KEEPORDER, NPY_NO_CASTING,
NULL);
if (iter == NULL) {
return -1;
}
/*
* The iternext function gets stored in a local variable
* so it can be called repeatedly in an efficient manner.
*/
iternext = NpyIter_GetIterNext(iter, NULL);
if (iternext == NULL) {
NpyIter_Deallocate(iter);
return -1;
}
/* The location of the data pointer which the iterator may update */
dataptr = NpyIter_GetDataPtrArray(iter);
/* The location of the stride which the iterator may update */
strideptr = NpyIter_GetInnerStrideArray(iter);
/* The location of the inner loop size which the iterator may update */
innersizeptr = NpyIter_GetInnerLoopSizePtr(iter);
nonzero_count = 0;
do {
/* Get the inner loop data/stride/count values */
char* data = *dataptr;
npy_intp stride = *strideptr;
npy_intp count = *innersizeptr;
/* This is a typical inner loop for NPY_ITER_EXTERNAL_LOOP */
while (count--) {
if (nonzero(data, self)) {
++nonzero_count;
}
data += stride;
}
/* Increment the iterator to the next inner loop */
} while(iternext(iter));
NpyIter_Deallocate(iter);
return nonzero_count;
}
Пример простой многократной итерации
Вот пример функции копирования, использующей итератор. Параметр order используется для управления компоновкой памяти выделенного результата, обычно желательно NPY_KEEPORDER.
PyObject *CopyArray(PyObject *arr, NPY_ORDER order)
{
NpyIter *iter;
NpyIter_IterNextFunc *iternext;
PyObject *op[2], *ret;
npy_uint32 flags;
npy_uint32 op_flags[2];
npy_intp itemsize, *innersizeptr, innerstride;
char **dataptrarray;
/*
* No inner iteration - inner loop is handled by CopyArray code
*/
flags = NPY_ITER_EXTERNAL_LOOP;
/*
* Tell the constructor to automatically allocate the output.
* The data type of the output will match that of the input.
*/
op[0] = arr;
op[1] = NULL;
op_flags[0] = NPY_ITER_READONLY;
op_flags[1] = NPY_ITER_WRITEONLY | NPY_ITER_ALLOCATE;
/* Construct the iterator */
iter = NpyIter_MultiNew(2, op, flags, order, NPY_NO_CASTING,
op_flags, NULL);
if (iter == NULL) {
return NULL;
}
/*
* Make a copy of the iternext function pointer and
* a few other variables the inner loop needs.
*/
iternext = NpyIter_GetIterNext(iter, NULL);
innerstride = NpyIter_GetInnerStrideArray(iter)[0];
itemsize = NpyIter_GetDescrArray(iter)[0]->elsize;
/*
* The inner loop size and data pointers may change during the
* loop, so just cache the addresses.
*/
innersizeptr = NpyIter_GetInnerLoopSizePtr(iter);
dataptrarray = NpyIter_GetDataPtrArray(iter);
/*
* Note that because the iterator allocated the output,
* it matches the iteration order and is packed tightly,
* so we don't need to check it like the input.
*/
if (innerstride == itemsize) {
do {
memcpy(dataptrarray[1], dataptrarray[0],
itemsize * (*innersizeptr));
} while (iternext(iter));
} else {
/* For efficiency, should specialize this based on item size... */
npy_intp i;
do {
npy_intp size = *innersizeptr;
char *src = dataptrarray[0], *dst = dataptrarray[1];
for(i = 0; i < size; i++, src += innerstride, dst += itemsize) {
memcpy(dst, src, itemsize);
}
} while (iternext(iter));
}
/* Get the result from the iterator object array */
ret = NpyIter_GetOperandArray(iter)[1];
Py_INCREF(ret);
if (NpyIter_Deallocate(iter) != NPY_SUCCEED) {
Py_DECREF(ret);
return NULL;
}
return ret;
}
Типы данных итератора
Структура итератора — внутренняя деталь, и код пользователя видит только неполную структуру.
-
NpyIter -
Это тип указателя, используемый для итератора. Доступ к его содержимому возможен только через API итератора.
-
NpyIter_Type -
Это тип, который предоставляет доступ к итератору в Python. В настоящее время нет API, предоставляющего доступ к значениям итератора, созданного в Python. Если итератор создан в Python, он должен использоваться в Python, и наоборот. Такой API, вероятно, будет создан в будущей версии.
-
NpyIter_IterNextFunc -
Это указатель на функцию для цикла итерации, возвращаемый
NpyIter_GetIterNext.
-
NpyIter_GetMultiIndexFunc -
Это указатель на функцию для получения текущего многомерного индекса итератора, возвращаемый
NpyIter_GetGetMultiIndex.
Создание и уничтожение
-
NpyIter* NpyIter_New(PyArrayObject* op, npy_uint32 flags, NPY_ORDER order, NPY_CASTING casting, PyArray_Descr* dtype) -
Создаёт итератор для данного объекта массива NumPy
op.Флаги, которые могут быть переданы в
flags— это любая комбинация глобальных и операционных флагов, документированных вNpyIter_MultiNew, за исключениемNPY_ITER_ALLOCATE.Любое значение перечисления
NPY_ORDERможно передать вorder. Для эффективной итерации лучше всего использоватьNPY_KEEPORDER, а другие порядки обеспечивают определённый порядок итерации.Любое значение перечисления
NPY_CASTINGможно передать вcasting. Значения включаютNPY_NO_CASTING,NPY_EQUIV_CASTING,NPY_SAFE_CASTING,NPY_SAME_KIND_CASTINGиNPY_UNSAFE_CASTING. Для возможности преобразований также необходимо включить копирование или буферизацию.Если
dtypeне равноNULL, то требуется этот тип данных. Если разрешено копирование, то будет создана временная копия, если данные допускают преобразование. Если включёнNPY_ITER_UPDATEIFCOPY, то при уничтожении итератора данные также будут скопированы обратно с другим преобразованием.Возвращает NULL, если возникла ошибка, в противном случае возвращает выделенный итератор.
Чтобы создать итератор, похожий на старый итератор, это должно сработать.
iter = NpyIter_New(op, NPY_ITER_READWRITE, NPY_CORDER, NPY_NO_CASTING, NULL);Если вы хотите изменить массив с выровненным
doubleкодом, но порядок не важен, то следует использовать это.dtype = PyArray_DescrFromType(NPY_DOUBLE); iter = NpyIter_New(op, NPY_ITER_READWRITE| NPY_ITER_BUFFERED| NPY_ITER_NBO| NPY_ITER_ALIGNED, NPY_KEEPORDER, NPY_SAME_KIND_CASTING, dtype); Py_DECREF(dtype);
-
NpyIter* NpyIter_MultiNew(npy_intp nop, PyArrayObject** op, npy_uint32 flags, NPY_ORDER order, NPY_CASTING casting, npy_uint32* op_flags, PyArray_Descr** op_dtypes) -
Создает итератор для трансляции массивов объектов
nop, предоставленных вop, используя стандартные правила трансляции NumPy.Любые значения перечисления
NPY_ORDERмогут быть переданы вorder. Для эффективной итерации наилучшим вариантом являетсяNPY_KEEPORDER, а другие порядки обеспечивают определенный порядок итерации. При использованииNPY_KEEPORDER, если вы также хотите гарантировать, что итерация не будет обращена вдоль оси, вы должны передать флагNPY_ITER_DONT_NEGATE_STRIDES.Любые значения перечисления
NPY_CASTINGмогут быть переданы вcasting. Значения включаютNPY_NO_CASTING,NPY_EQUIV_CASTING,NPY_SAFE_CASTING,NPY_SAME_KIND_CASTINGиNPY_UNSAFE_CASTING. Для разрешения преобразований также необходимо включить копирование или буферизацию.Если
op_dtypesнеNULL, он указывает тип данных илиNULLдля каждогоop[i].Возвращает NULL в случае ошибки, в противном случае возвращает выделенный итератор.
Флаги, которые могут быть переданы в
flags, относятся ко всему итератору:-
NPY_ITER_C_INDEX -
Приводит к тому, что итератор отслеживает развернутый плоский индекс, соответствующий порядку C. Этот вариант не может быть использован с
NPY_ITER_F_INDEX.
-
NPY_ITER_F_INDEX -
Приводит к тому, что итератор отслеживает развернутый плоский индекс, соответствующий порядку Fortran. Этот вариант не может быть использован с
NPY_ITER_C_INDEX.
-
NPY_ITER_MULTI_INDEX -
Приводит к тому, что итератор отслеживает многомерный индекс. Это предотвращает слияние осей для создания больших внутренних циклов. Если цикл также не буферизован и не отслеживается индекс (
NpyIter_RemoveAxisможет быть вызван), то размер итератора может быть-1для указания того, что итератор слишком большой. Это может произойти из-за сложной трансляции и приведет к ошибкам при установке диапазона итератора, удалении многомерного индекса или получении следующей функции. Однако возможно снова удалить оси и использовать итератор нормально, если размер достаточно мал после удаления.
-
NPY_ITER_EXTERNAL_LOOP -
Приводит к тому, что итератор пропускает итерацию внутреннего цикла, требуя, чтобы пользователь обрабатывал его сам.
Этот флаг несовместим с
NPY_ITER_C_INDEX,NPY_ITER_F_INDEXиNPY_ITER_MULTI_INDEX.
-
NPY_ITER_DONT_NEGATE_STRIDES -
Это влияет только на итератор, когда для параметра порядка указано
NPY_KEEPORDER. По умолчанию сNPY_KEEPORDERитератор обращает оси с отрицательными шагами, чтобы память проходилась в прямом направлении. Этот шаг отключается. Используйте этот флаг, если вы хотите использовать порядок хранения памяти осей, но не хотите, чтобы ось была обращена. Такое поведение, например, уnumpy.ravel(a, order='K').
-
NPY_ITER_COMMON_DTYPE -
Приводит к тому, что итератор преобразует все операнды в один общий тип данных, рассчитанный на основе правил повышения типа ufunc. Копирование или буферизация должны быть включены.
Если общий тип данных известен заранее, не используйте этот флаг. Вместо этого установите требуемый тип данных для всех операндов.
-
NPY_ITER_REFS_OK -
Указывает, что массивы со ссылками (массивы объектов или структурированные массивы, содержащие тип объекта) могут быть приняты и использованы в итераторе. Если этот флаг включён, вызывающий должен убедиться, что
NpyIter_IterationNeedsAPI(iter)истинно, в противном случае он не может освободить GIL во время итерации.
-
NPY_ITER_ZEROSIZE_OK -
Указывает, что массивы с размером ноль должны быть разрешены. Поскольку типичный цикл итерации не работает естественным образом с массивами нулевого размера, вы должны убедиться, что IterSize больше нуля, прежде чем входить в цикл итерации. В настоящее время проверяются только операнды, а не принудительная форма.
-
NPY_ITER_REDUCE_OK -
Разрешает доступные для записи операнды с размером измерения с нулевым шагом и размером больше единицы. Обратите внимание, что такие операнды должны быть доступны для чтения/записи.
При включенной буферизации также переключается на специальный режим буферизации, который уменьшает длину цикла по мере необходимости, чтобы не перезаписывать значения, которые уменьшаются.
Обратите внимание, что если вы хотите выполнить уменьшение на автоматически выделенном выходе, вы должны использовать
NpyIter_GetOperandArrayдля получения его ссылки, а затем установить каждое значение на единицу уменьшения перед выполнением цикла итерации. В случае буферизованного уменьшения это также означает, что вы должны указать флагNPY_ITER_DELAY_BUFALLOC, а затем перезапустить итератор после инициализации выделенного операнда для подготовки буферов.
-
NPY_ITER_RANGED -
Включает поддержку итерации по поддиапазонам всего диапазона
iterindex[0, NpyIter_IterSize(iter)). Используйте функциюNpyIter_ResetToIterIndexRangeдля указания диапазона итерации.Этот флаг может использоваться только с
NPY_ITER_EXTERNAL_LOOP, когдаNPY_ITER_BUFFEREDвключен. Это связано с тем, что без буферизации внутренний цикл всегда имеет размер наименьшего измерения итерации, а разрешение его разделения потребовало бы специальной обработки, фактически сделав его похожим на буферизованную версию.
-
NPY_ITER_BUFFERED -
Приводит к тому, что итератор сохраняет данные буферизации и использует буферизацию для удовлетворения требований к типу данных, выравниванию и порядку байтов. Чтобы буферизовать операнд, не указывайте флаги
NPY_ITER_COPYилиNPY_ITER_UPDATEIFCOPY, поскольку они переопределят буферизацию. Буферизация особенно полезна для кода Python, использующего итератор, позволяя обрабатывать большие блоки данных сразу, чтобы амортизировать накладные расходы интерпретатора Python.При использовании с
NPY_ITER_EXTERNAL_LOOPвнутренний цикл вызывающего может получить блоки данных большего размера, чем возможно без буферизации, из-за того, как организованы шаги.Обратите внимание, что если операнду задан флаг
NPY_ITER_COPYилиNPY_ITER_UPDATEIFCOPY, будет выполнена копия вместо буферизации. Буферизация всё равно произойдёт, если массив был транслирован, поэтому элементы должны быть дублированы для получения постоянного шага.В обычной буферизации размер каждого внутреннего цикла равен размеру буфера или, возможно, больше, если указан
NPY_ITER_GROWINNER. Если включёнNPY_ITER_REDUCE_OKи происходит уменьшение, внутренние циклы могут стать меньше в зависимости от структуры уменьшения.
-
NPY_ITER_GROWINNER -
При включенной буферизации это позволяет размеру внутреннего цикла увеличиваться, когда буферизация не требуется. Этот параметр лучше всего использовать при прямом прохождении всех данных, а не при работе с небольшими массивами временных значений для каждого внутреннего цикла.
-
NPY_ITER_DELAY_BUFALLOC -
При включенной буферизации это откладывает выделение буферов до вызова
NpyIter_Resetили другой функции сброса. Этот флаг существует для предотвращения нецелесообразного копирования данных буфера при создании нескольких копий буферизованного итератора для многопоточной итерации.Другое использование этого флага — для настройки операций уменьшения. После создания итератора и автоматического выделения выхода уменьшения итератором (обязательно использовать доступ READWRITE) его значение можно инициализировать до единицы уменьшения. Используйте
NpyIter_GetOperandArrayдля получения объекта. Затем вызовитеNpyIter_Resetдля выделения и заполнения буферов их начальными значениями.
-
-
NPY_ITER_COPY_IF_OVERLAP -
Если какой-либо операнд записи перекрывает какой-либо операнд чтения, все перекрытия устраняются путём создания временных копий (при необходимости включения UPDATEIFCOPY для операндов записи). Пара операндов перекрывается, если существует адрес памяти, содержащий данные, общие для обеих массивов.
Поскольку точное определение перекрытия имеет экспоненциальную временную сложность от количества измерений, решение принимается на основе эвристик, что приводит к ложным срабатываниям (ненужные копии в необычных случаях), но не к ложноотрицательным результатам.
Если существует какое-либо перекрытие чтение/запись, этот флаг гарантирует, что результат операции будет таким же, как если бы все операнды были скопированы. В случаях, когда требуется создание копий, результат вычисления может быть неопределённым без этого флага!
Флаги, которые могут быть переданы в
op_flags[i], где0 <= i < nop:-
NPY_ITER_READWRITE
-
NPY_ITER_READONLY
-
NPY_ITER_WRITEONLY -
Указывает, как пользователь итератора будет читать или писать в
op[i]. Для каждого операнда должен быть указан ровно один из этих флагов.
-
NPY_ITER_COPY -
Разрешает создание копии
op[i]в случае, если она не соответствует требованиям по типу данных или выравниванию, заданным флагами и параметрами конструктора.
-
NPY_ITER_UPDATEIFCOPY -
Вызывает
NPY_ITER_COPY, и когда операнд массива помечен для записи и копируется, данные из копии копируются обратно вop[i]при уничтожении итератора.Если операнд помечен как только для записи и требуется копия, будет создан неинициализированный временный массив, а затем он будет скопирован обратно в
op[i]при уничтожении, вместо выполнения ненужной операции копирования.
-
NPY_ITER_NBO
-
NPY_ITER_ALIGNED
-
NPY_ITER_CONTIG -
Заставляет итератор предоставлять данные для
op[i]в родном байтовом порядке, выровненные согласно требованиям dtype, непрерывные или любая комбинация.По умолчанию итератор генерирует указатели в предоставленные массивы, которые могут быть выровнены или не выровнены, а также с любым байтовым порядком. Если копирование или буферизация не включены, и данные операнда не удовлетворяют ограничениям, будет поднято исключение.
Ограничение непрерывности относится только к внутреннему циклу; последовательные внутренние циклы могут иметь произвольные изменения указателей.
Если запрашиваемый тип данных имеет неродной байтовый порядок, флаг NBO переопределяет его, и запрашиваемый тип данных преобразуется в родной байтовый порядок.
-
NPY_ITER_ALLOCATE -
Это для выходных массивов и требует, чтобы был установлен флаг
NPY_ITER_WRITEONLYилиNPY_ITER_READWRITE. Еслиop[i]равен NULL, создаётся новый массив с конечными размерами трансляции и структурой, соответствующей порядку итерации итератора.Когда
op[i]равен NULL, запрашиваемый тип данныхop_dtypes[i]также может быть NULL, в этом случае он автоматически генерируется из типов данных массивов, помеченных как читаемые. Правила генерации типа данных такие же, как для UFuncs. Важно отметить обработку байтового порядка в выбранном типе данных. Если имеется ровно один вход, тип данных входа используется как есть. В противном случае, если несколько типов данных входа комбинируются вместе, вывод будет в родном байтовом порядке.После выделения с этим флагом вызывающая сторона может получить новый массив, вызвав
NpyIter_GetOperandArrayи получив i-й объект в возвращённом массиве C. Вызывающая сторона должна вызвать Py_INCREF на нём, чтобы получить ссылку на массив.
-
NPY_ITER_NO_SUBTYPE -
Для использования с
NPY_ITER_ALLOCATEэтот флаг отключает выделение подтипа массива для вывода, заставляя его быть прямым ndarray.TODO: Возможно, лучше было бы ввести функцию
NpyIter_GetWrappedOutputи убрать этот флаг?
-
NPY_ITER_NO_BROADCAST -
Обеспечивает, что вход или вывод точно соответствует размерам итерации.
-
NPY_ITER_ARRAYMASK -
Введено в версии 1.7.
Указывает, что этот операнд является маской для выбора элементов при записи в операнды, к которым применён флаг
NPY_ITER_WRITEMASKED. Только один операнд может иметь флагNPY_ITER_ARRAYMASK.Тип данных операнда с этим флагом должен быть либо
NPY_BOOL,NPY_MASK, или структурированным типом данных, поля которого являются допустимыми типами данных маски. В последнем случае он должен совпадать со структурированным операндом, имеющим флаг WRITEMASKED, так как он задаёт маску для каждого поля этого массива.Этот флаг влияет только на запись из буфера обратно в массив. Это означает, что если операнд также имеет флаг
NPY_ITER_READWRITEилиNPY_ITER_WRITEONLY, код, выполняющий итерацию, может записывать в этот операнд, чтобы управлять тем, какие элементы останутся нетронутыми, а какие будут изменены. Это полезно, когда маска должна быть комбинацией входных масок, например. Значения масок могут быть созданы с помощью функцииNpyMask_Create.
-
NPY_ITER_WRITEMASKED -
Введено в версии 1.7.
Указывает, что только элементы, которые операнд с флагом ARRAYMASK указывает, предназначены для изменения во время итерации. В общем случае итератор не навязывает это требование, и код, выполняющий итерацию, сам должен следовать этому условию. Код может использовать встроенную функцию
NpyMask_IsExposedдля проверки того, разрешает ли маска запись в конкретном элементе.Когда используется этот флаг, и этот операнд буферизуется, это меняет способ копирования данных из буфера в массив. Используется функция маскированного копирования, которая копирует только те элементы из буфера, для которых
NpyMask_IsExposedвозвращает true для соответствующего элемента в операнде ARRAYMASK.
-
NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE -
При проверке перекрытия в памяти предполагается, что операнды с включённым флагом
NPY_ITER_OVERLAP_ASSUME_ELEMENTWISEобращаются только в порядке итерации.Это позволяет итератору выводить информацию о зависимости данных, возможно, избегая ненужных копий.
Этот флаг действует только в случае, если
NPY_ITER_COPY_IF_OVERLAPвключён для итератора.
-
-
NpyIter* NpyIter_AdvancedNew(npy_intp nop, PyArrayObject** op, npy_uint32 flags, NPY_ORDER order, NPY_CASTING casting, npy_uint32* op_flags, PyArray_Descr** op_dtypes, int oa_ndim, int** op_axes, npy_intp* itershape, npy_intp buffersize) -
Расширяет
NpyIter_MultiNewнесколькими расширенными опциями, обеспечивающими больший контроль над трансляцией и буферизацией.Если -1/NULL передаются в
oa_ndim,op_axes,itershape, иbuffersize, это эквивалентноNpyIter_MultiNew.Параметр
oa_ndim, когда не равен нулю или -1, задаёт количество измерений, которые будут итерироваться с настраиваемой трансляцией. Если он задан,op_axesдолжен, аitershapeможет также быть задан. Параметрop_axesпозволяет детально управлять тем, как оси массивов операндов объединяются и итерируются. Вop_axes, необходимо предоставить массив указателейnopна массивы размеромoa_ndimтипаnpy_intp. Если элемент вop_axesравен NULL, будут применяться обычные правила трансляции. Вop_axes[j][i]хранится либо допустимая осьop[j], либо -1, что означаетnewaxis. Внутри каждого массиваop_axes[j]оси не могут повторяться. Следующий пример демонстрирует, как обычная трансляция применяется к 3-мерному массиву, 2-мерному массиву, 1-мерному массиву и скаляру.Примечание: До NumPy 1.8
oa_ndim == 0` was used for signalling that that ``op_axesиitershapeне используются. Это устарело и должно быть заменено на -1. Для лучшей обратной совместимости в этом случае следует использоватьNpyIter_MultiNew.int oa_ndim = 3; /* # iteration axes */ int op0_axes[] = {0, 1, 2}; /* 3-D operand */ int op1_axes[] = {-1, 0, 1}; /* 2-D operand */ int op2_axes[] = {-1, -1, 0}; /* 1-D operand */ int op3_axes[] = {-1, -1, -1} /* 0-D (scalar) operand */ int* op_axes[] = {op0_axes, op1_axes, op2_axes, op3_axes};Параметр
itershapeпозволяет принудительно задать определённую форму итерации для итератора. Это массив длинойoa_ndim. Когда элемент отрицательный, его значение определяется из операндов. Этот параметр позволяет автоматически выделять выходные значения с дополнительными измерениями, которые не соответствуют ни одному измерению входных данных.Если
buffersizeравно нулю, используется размер буфера по умолчанию, в противном случае он указывает размер буфера.Возвращает NULL при ошибке, иначе возвращает выделенный итератор.
-
NpyIter* NpyIter_Copy(NpyIter* iter) -
Создает копию данного итератора. Эта функция в основном предназначена для многопоточной итерации данных.
TODO: Переместить эту информацию в раздел о многопоточной итерации.
Рекомендуемый подход к многопоточной итерации состоит в том, чтобы сначала создать итератор с флагами
NPY_ITER_EXTERNAL_LOOP,NPY_ITER_RANGED,NPY_ITER_BUFFERED,NPY_ITER_DELAY_BUFALLOCи, возможно,NPY_ITER_GROWINNER. Создайте копию этого итератора для каждого потока (кроме одного для первого итератора). Затем, возьмите диапазон индексов итерации[0, NpyIter_GetIterSize(iter))и разделите его на задачи, например, используя цикл TBB parallel_for. Когда поток получает задачу для выполнения, он использует свою копию итератора, вызываяNpyIter_ResetToIterIndexRangeи итерирует по всему диапазону.При использовании итератора в многопоточном коде или в коде, не удерживающем Python GIL, необходимо позаботиться о том, чтобы вызывать только функции, которые безопасны в этом контексте.
NpyIter_Copyнельзя безопасно вызывать без Python GIL, потому что он увеличивает ссылки Python.Reset*и некоторые другие функции могут быть безопасно вызваны, передав параметрerrmsgкак не-NULL, чтобы функции возвращали ошибки через него вместо установки исключения Python.
-
int NpyIter_RemoveAxis(NpyIter* iter, int axis)`` -
Удаляет ось из итерации. Для этого требуется, чтобы
NPY_ITER_MULTI_INDEXбыл установлен для создания итератора, и не работает, если буферизация включена или отслеживается индекс. Эта функция также сбрасывает итератор в исходное состояние.Это полезно для настройки цикла накопления, например. Сначала можно создать итератор со всеми измерениями, включая ось накопления, чтобы выходной результат создавался правильно. Затем ось накопления можно удалить, и вычисление выполнить вложенным образом.
ВНИМАНИЕ: Эта функция может изменить внутреннее расположение памяти итератора. Любые кэшированные функции или указатели итератора должны быть получены заново! Диапазон итератора также будет сброшен.
Возвращает
NPY_SUCCEEDилиNPY_FAIL.
-
int NpyIter_RemoveMultiIndex(NpyIter* iter) -
Если итератор отслеживает многоиндекс, эта функция удаляет поддержку многоиндексов и выполняет дополнительные оптимизации итератора, возможные, если многоиндексы не нужны. Эта функция также сбрасывает итератор в исходное состояние.
ВНИМАНИЕ: Эта функция может изменить внутреннее расположение памяти итератора. Любые кэшированные функции или указатели итератора должны быть получены заново!
После вызова этой функции
NpyIter_HasMultiIndex(iter)вернет false.Возвращает
NPY_SUCCEEDилиNPY_FAIL.
-
int NpyIter_EnableExternalLoop(NpyIter* iter) -
Если была вызвана
NpyIter_RemoveMultiIndex, вы можете включить флагNPY_ITER_EXTERNAL_LOOP. Этот флаг не допускается вместе сNPY_ITER_MULTI_INDEX, поэтому эта функция предназначена для включения функции после вызоваNpyIter_RemoveMultiIndex. Эта функция также сбрасывает итератор в исходное состояние.ВНИМАНИЕ: Эта функция изменяет внутреннюю логику итератора. Любые кэшированные функции или указатели итератора должны быть получены заново!
Возвращает
NPY_SUCCEEDилиNPY_FAIL.
-
int NpyIter_Deallocate(NpyIter* iter) -
Освобождает объект итератора. Это также освобождает все сделанные копии, вызывая поведение UPDATEIFCOPY при необходимости.
Возвращает
NPY_SUCCEEDилиNPY_FAIL.
-
int NpyIter_Reset(NpyIter* iter, char** errmsg) -
Сбрасывает итератор в исходное состояние, в начало диапазона итерации.
Возвращает
NPY_SUCCEEDилиNPY_FAIL. Если errmsg не NULL, исключение Python не устанавливается, когда возвращаетсяNPY_FAIL. Вместо этого *errmsg устанавливается в сообщение об ошибке. Когда errmsg не NULL, функция может быть безопасно вызвана без удержания Python GIL.
-
int NpyIter_ResetToIterIndexRange(NpyIter* iter, npy_intp istart, npy_intp iend, char** errmsg) -
Сбрасывает итератор и ограничивает его диапазоном
iterindex[istart, iend). См.NpyIter_Copyдля объяснения использования этого для многопоточной итерации. Требуется, чтобы флагNPY_ITER_RANGEDбыл передан конструктору итератора.Если вы хотите сбросить диапазон
iterindexи базовые указатели одновременно, можно сделать следующее, чтобы избежать лишнего копирования буфера (не забудьте добавить проверки на возвращаемые значения кода при копировании этого кода)./* Set to a trivial empty range */ NpyIter_ResetToIterIndexRange(iter, 0, 0); /* Set the base pointers */ NpyIter_ResetBasePointers(iter, baseptrs); /* Set to the desired range */ NpyIter_ResetToIterIndexRange(iter, istart, iend);
Возвращает
NPY_SUCCEEDилиNPY_FAIL. Если errmsg не NULL, исключение Python не устанавливается, когда возвращаетсяNPY_FAIL. Вместо этого *errmsg устанавливается в сообщение об ошибке. Когда errmsg не NULL, функция может быть безопасно вызвана без удержания Python GIL.
-
int NpyIter_ResetBasePointers(NpyIter *iter, char** baseptrs, char** errmsg) -
Сбрасывает итератор в исходное состояние, но использует значения в
baseptrsдля данных вместо указателей из массивов, по которым выполняется итерация. Эта функция предназначена для использования вместе с параметромop_axesкодом вложенной итерации с двумя или более итераторами.Возвращает
NPY_SUCCEEDилиNPY_FAIL. Если errmsg не NULL, исключение Python не устанавливается, когда возвращаетсяNPY_FAIL. Вместо этого *errmsg устанавливается в сообщение об ошибке. Когда errmsg не NULL, функция может быть безопасно вызвана без удержания Python GIL.TODO: Переместить следующее в отдельный раздел о вложенных итераторах.
Создание итераторов для вложенной итерации требует осторожности. Все операнды итератора должны точно совпадать, или вызовы
NpyIter_ResetBasePointersбудут недействительными. Это означает, что автоматические копии и выделение выходных данных не должны использоваться бездумно. Можно по-прежнему использовать функции автоматического преобразования и приведения типов итератора, создав один из итераторов со всеми параметрами преобразования, затем взяв выделенные операнды с помощью функцииNpyIter_GetOperandArrayи передав их в конструкторы для остальных итераторов.ВНИМАНИЕ: При создании итераторов для вложенной итерации код не должен использовать измерение более одного раза в различных итераторах. Если это сделать, вложенная итерация приведет к указателям за пределами границ во время итерации.
ВНИМАНИЕ: При создании итераторов для вложенной итерации буферизация может применяться только к самому внутреннему итератору. Если буферизованный итератор используется как источник для
baseptrs, он будет указывать на небольшой буфер вместо массива, и внутренняя итерация будет недействительной.Шаблон использования вложенных итераторов следующий:
NpyIter *iter1, *iter1; NpyIter_IterNextFunc *iternext1, *iternext2; char **dataptrs1; /* * With the exact same operands, no copies allowed, and * no axis in op_axes used both in iter1 and iter2. * Buffering may be enabled for iter2, but not for iter1. */ iter1 = ...; iter2 = ...; iternext1 = NpyIter_GetIterNext(iter1); iternext2 = NpyIter_GetIterNext(iter2); dataptrs1 = NpyIter_GetDataPtrArray(iter1); do { NpyIter_ResetBasePointers(iter2, dataptrs1); do { /* Use the iter2 values */ } while (iternext2(iter2)); } while (iternext1(iter1));
-
int NpyIter_GotoMultiIndex(NpyIter* iter, npy_intp* multi_index) -
Настраивает итератор на указание на индексы
ndim, на которые указываетmulti_index. Возвращает ошибку, если многоиндекс не отслеживается, индексы находятся за пределами границ или итерация внутреннего цикла отключена.Возвращает
NPY_SUCCEEDилиNPY_FAIL.
-
int NpyIter_GotoIndex(NpyIter* iter, npy_intp index) -
Настраивает итератор на указание на указанный
index. Если итератор был создан с флагомNPY_ITER_C_INDEX,index— индекс в порядке C, а если итератор был создан с флагомNPY_ITER_F_INDEX,index— индекс в порядке Fortran. Возвращает ошибку, если не отслеживается индекс, индекс находится за пределами границ или итерация внутреннего цикла отключена.Возвращает
NPY_SUCCEEDилиNPY_FAIL.
-
npy_intp NpyIter_GetIterSize(NpyIter* iter) -
Возвращает количество итерируемых элементов. Это произведение всех измерений в форме. Когда отслеживается многоиндекс (и может быть вызван
NpyIter_RemoveAxis) размер может быть-1для указания того, что итератор слишком большой. Такой итератор недействителен, но может стать действительным после вызоваNpyIter_RemoveAxis. Проверка этого случая не требуется.
-
npy_intp NpyIter_GetIterIndex(NpyIter* iter) -
Возвращает
iterindexитератора, который является индексом, соответствующим порядку итерации итератора.
-
void NpyIter_GetIterIndexRange(NpyIter* iter, npy_intp* istart, npy_intp* iend) -
Возвращает
iterindexподдиапазон, по которому выполняется итерация. ЕслиNPY_ITER_RANGEDне был указан, это всегда возвращает диапазон[0, NpyIter_IterSize(iter)).
-
int NpyIter_GotoIterIndex(NpyIter* iter, npy_intp iterindex) -
Настраивает итератор на указание на указанный
iterindex. IterIndex — индекс, соответствующий порядку итерации итератора. Возвращает ошибку, еслиiterindexнаходится за пределами границ, буферизация включена или итерация внутреннего цикла отключена.Возвращает
NPY_SUCCEEDилиNPY_FAIL.
-
npy_bool NpyIter_HasDelayedBufAlloc(NpyIter* iter) -
Возвращает 1, если флаг
NPY_ITER_DELAY_BUFALLOCбыл передан в конструктор итератора, и пока не было выполнено ни одного из вызовов функций Reset, иначе возвращает 0.
-
npy_bool NpyIter_HasExternalLoop(NpyIter* iter) -
Возвращает 1, если вызывающей стороне необходимо обработать вложенный одномерный цикл, или 0, если итератор обрабатывает все циклы. Это контролируется флагом конструктора
NPY_ITER_EXTERNAL_LOOPилиNpyIter_EnableExternalLoop.
-
npy_bool NpyIter_HasMultiIndex(NpyIter* iter) -
Возвращает 1, если итератор был создан с флагом
NPY_ITER_MULTI_INDEX, иначе 0.
-
npy_bool NpyIter_HasIndex(NpyIter* iter) -
Возвращает 1, если итератор был создан с флагом
NPY_ITER_C_INDEXилиNPY_ITER_F_INDEX, иначе 0.
-
npy_bool NpyIter_RequiresBuffering(NpyIter* iter) -
Возвращает 1, если итератор требует буферизации, что происходит, когда операнду требуется преобразование или выравнивание, и его нельзя использовать напрямую.
-
npy_bool NpyIter_IsBuffered(NpyIter* iter) -
Возвращает 1, если итератор был создан с флагом
NPY_ITER_BUFFERED, иначе 0.
-
npy_bool NpyIter_IsGrowInner(NpyIter* iter) -
Возвращает 1, если итератор был создан с флагом
NPY_ITER_GROWINNER, иначе 0.
-
npy_intp NpyIter_GetBufferSize(NpyIter* iter) -
Если итератор буферизован, возвращает размер используемого буфера, иначе возвращает 0.
-
int NpyIter_GetNDim(NpyIter* iter) -
Возвращает количество измерений, по которым выполняется итерация. Если в конструкторе итератора не был запрошен многомерный индекс, это значение может быть меньше, чем количество измерений в исходных объектах.
-
int NpyIter_GetNOp(NpyIter* iter) -
Возвращает количество операндов в итераторе.
Когда
NPY_ITER_USE_MASKNAиспользуется с операндом, новый операнд добавляется в конец списка операндов в итераторе для отслеживания маски NA этого операнда. Таким образом, это равно количеству операндов, переданных в конструктор, плюс количество операндов, для которых был указан флагNPY_ITER_USE_MASKNA.
-
int NpyIter_GetFirstMaskNAOp(NpyIter* iter) -
Новая в версии 1.7.
Возвращает индекс первого операнда маски NA в массиве. Это значение равно количеству операндов, переданных в конструктор.
-
npy_intp* NpyIter_GetAxisStrideArray(NpyIter* iter, int axis) -
Получает массив шагов для указанной оси. Требует, чтобы итератор отслеживал многомерный индекс и чтобы буферизация не была включена.
Это может быть использовано, когда вы хотите каким-то образом сопоставить оси операндов, а затем удалить их с помощью
NpyIter_RemoveAxisдля обработки их вручную. Вызвав эту функцию до удаления осей, вы можете получить шаги для ручной обработки.Возвращает
NULLпри ошибке.
-
int NpyIter_GetShape(NpyIter* iter, npy_intp* outshape) -
Возвращает расширенную форму итератора в
outshape. Это можно вызвать только для итератора, который отслеживает многомерный индекс.Возвращает
NPY_SUCCEEDилиNPY_FAIL.
-
PyArray_Descr** NpyIter_GetDescrArray(NpyIter* iter) -
Возвращает указатель на
nopтипы данных Descrs объектов, по которым выполняется итерация. Результат указывает наiter, поэтому вызывающая сторона не получает никаких ссылок на Descrs.Этот указатель можно кэшировать до цикла итерации, вызов
iternextне изменит его.
-
PyObject** NpyIter_GetOperandArray(NpyIter* iter) -
Возвращает указатель на
nopоперанды PyObjects, по которым выполняется итерация. Результат указывает наiter, поэтому вызывающая сторона не получает никаких ссылок на PyObjects.
-
npy_int8* NpyIter_GetMaskNAIndexArray(NpyIter* iter) -
Новая в версии 1.7.
Возвращает указатель на
nopиндексы, которые сопоставляют операнды конструирования сNPY_ITER_USE_MASKNAфлагами соответствующим операндам маски NA и наоборот. Для операндов, которые не были помечены флагомNPY_ITER_USE_MASKNA, этот массив содержит отрицательные значения.
-
PyObject* NpyIter_GetIterView(NpyIter* iter, npy_intp i) -
Возвращает ссылку на новый вид ndarray, который является представлением i-го объекта в массиве
NpyIter_GetOperandArray, чьи размеры и шаги соответствуют внутреннему оптимизированному шаблону итерации. Итерация по этому представлению в порядке C эквивалентна порядку итерации итератора.Например, если итератор был создан с одним массивом в качестве входных данных и было возможно переупорядочить все его оси и затем свернуть его в одну итерацию с определенными шагами, это вернёт представление одномерного массива.
-
void NpyIter_GetReadFlags(NpyIter* iter, char* outreadflags) -
Заполняет
nopфлаги. Устанавливаетoutreadflags[i]в 1, еслиop[i]может быть прочитано, и в 0, если нет.
-
void NpyIter_GetWriteFlags(NpyIter* iter, char* outwriteflags) -
Заполняет
nopфлаги. Устанавливаетoutwriteflags[i]в 1, еслиop[i]может быть записано, и в 0, если нет.
-
int NpyIter_CreateCompatibleStrides(NpyIter* iter, npy_intp itemsize, npy_intp* outstrides) -
Создаёт набор шагов, которые такие же, как шаги выходного массива, созданного с флагом
NPY_ITER_ALLOCATE, где NULL был передан для op_axes. Это для данных, упакованных непрерывно, но не обязательно в порядке C или Fortran. Это следует использовать вместе сNpyIter_GetShapeиNpyIter_GetNDimс флагомNPY_ITER_MULTI_INDEX, переданным в конструктор.Сценарий использования этой функции заключается в том, чтобы согласовать форму и структуру итератора и добавить одно или несколько измерений. Например, для генерации вектора на значение входа для численного градиента вы передаёте ndim*itemsize для itemsize, а затем добавляете другое измерение в конец с размером ndim и шагом itemsize. Для вычисления матрицы Гессе вы делаете то же самое, но добавляете два измерения или используете симметрию и упаковываете её в 1 измерение с определённым кодированием.
Эта функция может быть вызвана только, если итератор отслеживает многомерный индекс и если
NPY_ITER_DONT_NEGATE_STRIDESиспользовался для предотвращения итерации оси в обратном порядке.Если массив создан с помощью этого метода, простое добавление «itemsize» для каждой итерации пройдёт по новому массиву, соответствующему итератору.
Возвращает
NPY_SUCCEEDилиNPY_FAIL.
-
npy_bool NpyIter_IsFirstVisit(NpyIter* iter, int iop) -
Новая в версии 1.7.
Проверяет, является ли это первый раз, когда элементы указанного операнда сокращения, на который указывает итератор, встречаются впервые. Функция возвращает разумный ответ для операндов сокращения и когда буферизация отключена. Ответ может быть неверным для буферизованных операндов, не являющихся операндами сокращения.
Эта функция предназначена для использования только в режиме EXTERNAL_LOOP и даст некоторые неправильные ответы, когда этот режим не включён.
Если эта функция возвращает true, вызывающая сторона также должна проверить шаг внутреннего цикла операнда, потому что если этот шаг равен 0, то только первый элемент самого внутреннего внешнего цикла посещается впервые.
ВНИМАНИЕ: По соображениям производительности ‘iop’ не проверяется на границы, не подтверждается, что ‘iop’ на самом деле является операндом сокращения, и не подтверждается, что режим EXTERNAL_LOOP включён. Эти проверки являются обязанностью вызывающей стороны и должны выполняться вне любых вложенных циклов.
Функции для итерации
-
NpyIter_IterNextFunc* NpyIter_GetIterNext(NpyIter* iter, char** errmsg) -
Возвращает указатель на функцию для итерации. Специализированная версия указателя на функцию может быть рассчитана этой функцией вместо хранения в структуре итератора. Таким образом, для достижения хорошей производительности требуется сохранить указатель на функцию в переменной, а не извлекать для каждой итерации цикла.
Возвращает NULL, если произошла ошибка. Если errmsg не NULL, исключение Python не устанавливается при возвращении
NPY_FAIL. Вместо этого *errmsg устанавливается в сообщение об ошибке. Когда errmsg не NULL, функция может безопасно вызываться без блокировки Python GIL.Типичная конструкция цикла выглядит следующим образом.
NpyIter_IterNextFunc *iternext = NpyIter_GetIterNext(iter, NULL); char** dataptr = NpyIter_GetDataPtrArray(iter); do { /* use the addresses dataptr[0], ... dataptr[nop-1] */ } while(iternext(iter));Когда указан
NPY_ITER_EXTERNAL_LOOP, типичная внутренняя конструкция цикла выглядит следующим образом.NpyIter_IterNextFunc *iternext = NpyIter_GetIterNext(iter, NULL); char** dataptr = NpyIter_GetDataPtrArray(iter); npy_intp* stride = NpyIter_GetInnerStrideArray(iter); npy_intp* size_ptr = NpyIter_GetInnerLoopSizePtr(iter), size; npy_intp iop, nop = NpyIter_GetNOp(iter); do { size = *size_ptr; while (size--) { /* use the addresses dataptr[0], ... dataptr[nop-1] */ for (iop = 0; iop < nop; ++iop) { dataptr[iop] += stride[iop]; } } } while (iternext());Обратите внимание, что мы используем массив dataptr внутри итератора, а не копируем значения во временную локальную переменную. Это возможно, потому что при вызове
iternext(), эти указатели будут перезаписаны новыми значениями, а не инкрементально обновляться.Если используется буфер фиксированного размера во время компиляции (оба флага
NPY_ITER_BUFFEREDиNPY_ITER_EXTERNAL_LOOP), внутренний размер также может использоваться как сигнал. Размер гарантированно станет нулём, когдаiternext()возвращает false, позволяя использовать следующую конструкцию цикла. Обратите внимание, что если вы используете эту конструкцию, не следует передаватьNPY_ITER_GROWINNERв качестве флага, так как это может привести к большему размеру в некоторых случаях./* The constructor should have buffersize passed as this value */ #define FIXED_BUFFER_SIZE 1024 NpyIter_IterNextFunc *iternext = NpyIter_GetIterNext(iter, NULL); char **dataptr = NpyIter_GetDataPtrArray(iter); npy_intp *stride = NpyIter_GetInnerStrideArray(iter); npy_intp *size_ptr = NpyIter_GetInnerLoopSizePtr(iter), size; npy_intp i, iop, nop = NpyIter_GetNOp(iter); /* One loop with a fixed inner size */ size = *size_ptr; while (size == FIXED_BUFFER_SIZE) { /* * This loop could be manually unrolled by a factor * which divides into FIXED_BUFFER_SIZE */ for (i = 0; i < FIXED_BUFFER_SIZE; ++i) { /* use the addresses dataptr[0], ... dataptr[nop-1] */ for (iop = 0; iop < nop; ++iop) { dataptr[iop] += stride[iop]; } } iternext(); size = *size_ptr; } /* Finish-up loop with variable inner size */ if (size > 0) do { size = *size_ptr; while (size--) { /* use the addresses dataptr[0], ... dataptr[nop-1] */ for (iop = 0; iop < nop; ++iop) { dataptr[iop] += stride[iop]; } } } while (iternext());
-
NpyIter_GetMultiIndexFunc *NpyIter_GetGetMultiIndex(NpyIter* iter, char** errmsg) -
Возвращает указатель на функцию для получения текущего многомерного индекса итератора. Возвращает NULL, если итератор не отслеживает многомерный индекс. Рекомендуется кэшировать этот указатель на функцию в локальной переменной перед циклом итерации.
Возвращает NULL, если произошла ошибка. Если errmsg не NULL, исключение Python не устанавливается при возвращении
NPY_FAIL. Вместо этого *errmsg устанавливается в сообщение об ошибке. При errmsg не NULL, функция может безопасно вызываться без блокировки Python GIL.
-
char** NpyIter_GetDataPtrArray(NpyIter* iter) -
Возвращает указатель на массив указателей на данные
nop. ЕслиNPY_ITER_EXTERNAL_LOOPне был указан, каждый указатель на данные указывает на текущий элемент данных итератора. Если внутренняя итерация не была указана, он указывает на первый элемент данных внутреннего цикла.Этот указатель можно кэшировать перед циклом итерации; вызов
iternextне изменит его. Эту функцию можно безопасно вызывать без блокировки Python GIL.
-
char** NpyIter_GetInitialDataPtrArray(NpyIter* iter) -
Получает массив указателей на данные непосредственно в массивы (никогда не в буферы), соответствующие индексу итерации 0.
Эти указатели отличаются от указателей, принимаемых
NpyIter_ResetBasePointers, потому что направление по некоторым осям может быть обратным.Эту функцию можно безопасно вызывать без блокировки Python GIL.
-
npy_intp* NpyIter_GetIndexPtr(NpyIter* iter) -
Возвращает указатель на отслеживаемый индекс или NULL, если индекс не отслеживается. Он может быть использован только если один из флагов
NPY_ITER_C_INDEXилиNPY_ITER_F_INDEXбыл указан во время создания.
Когда используется флаг NPY_ITER_EXTERNAL_LOOP, код должен знать параметры для выполнения внутреннего цикла. Эти функции предоставляют эту информацию.
-
npy_intp* NpyIter_GetInnerStrideArray(NpyIter* iter) -
Возвращает указатель на массив
nopшагов, по одному для каждого итерируемого объекта, который будет использоваться внутренним циклом.Этот указатель можно кэшировать перед циклом итерации; вызов
iternextне изменит его. Эту функцию можно безопасно вызывать без блокировки Python GIL.ПРЕДУПРЕЖДЕНИЕ: Хотя указатель можно кэшировать, его значения могут измениться, если итератор буферизован.
-
npy_intp* NpyIter_GetInnerLoopSizePtr(NpyIter* iter) -
Возвращает указатель на количество итераций, которые должен выполнить внутренний цикл.
Этот адрес можно кэшировать перед циклом итерации; вызов
iternextне изменит его. Само значение может меняться во время итерации, особенно если включена буферизация. Эту функцию можно безопасно вызывать без блокировки Python GIL.
-
void NpyIter_GetInnerFixedStrideArray(NpyIter* iter, npy_intp* out_strides) -
Получает массив шагов, которые являются фиксированными или не будут изменяться во время всей итерации. Для шагов, которые могут изменяться, в шаг помещается значение NPY_MAX_INTP.
После подготовки итератора к итерации (после сброса, если
NPY_DELAY_BUFALLOCиспользовался), вызовите эту функцию, чтобы получить шаги, которые могут быть использованы для выбора быстрой функции внутреннего цикла. Например, если шаг равен 0, это означает, что внутренний цикл всегда может загрузить свое значение в переменную один раз, а затем использовать переменную на протяжении всего цикла, или если шаг равен itemsize, может быть использована непрерывная версия для этого операнда.Эту функцию можно безопасно вызывать без блокировки Python GIL.
Преобразование из предыдущих итераторов NumPy
Старый API итераторов включает функции, такие как PyArrayIter_Check, PyArray_Iter* и PyArray_ITER_*. Массив многомерных итераторов включает PyArray_MultiIter*, PyArray_Broadcast и PyArray_RemoveSmallest. Новый дизайн итераторов заменяет все эти функции одним объектом и соответствующим API. Одна из целей нового API заключается в том, чтобы все используемые существующие итераторы можно было заменить новым итератором без значительных усилий. В версии 1.6 основным исключением из этого правила является итератор соседства, у которого нет соответствующих функций в этом итераторе.
Вот таблица преобразования, указывающая, какие функции следует использовать с новым итератором:
© 2005–2019 NumPy Developers
Licensed under the 3-clause BSD License.
https://docs.scipy.org/doc/numpy-1.14.5/reference/c-api.iterator.html