API итератора массивов
Новая версия 1.6.
Итератор массивов
Итератор массивов объединяет ключевые возможности ufuncs, позволяя коду пользователя поддерживать такие функции, как параметры вывода, сохранение расположения памяти и буферизацию данных с неправильным выравниванием или типом, без необходимости сложных кодировок.
На этой странице описан API итератора. Итератор называется 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 -
Указывает, что массивы с размером 0 должны быть разрешены. Поскольку типичный цикл итерации не работает с массивами нулевого размера, необходимо убедиться, что 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_READWRITEилиNPY_ITER_WRITEONLYдля операнда, предоставленного пользователем, может вызватьWRITEBACKIFCOPY`семантику. Данные будут записаны обратно в исходный массив при вызовеNpyIter_Deallocate.
-
NPY_ITER_COPY -
Разрешить копирование
op[i]в случае, если он не соответствует требованиям к типу данных или выравниванию, как указано в флагах и параметрах конструктора.
-
NPY_ITER_UPDATEIFCOPY -
Вызывает
NPY_ITER_COPY, и когда операнд массива помечается для записи и копируется, вызывает копирование данных из копии обратно вop[i]при вызовеNpyIter_Deallocate.Если операнд помечен как только для записи и требуется копия, будет создан неинициализированный временный массив, а затем скопирован обратно в
op[i]при вызовеNpyIter_Deallocate, вместо выполнения ненужной операции копирования.
-
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, код, выполняющий итерацию, может записывать в этот операнд для управления элементами, которые будут оставлены без изменений, и элементами, которые будут изменены. Это полезно, когда маска должна быть комбинацией входных масок.
-
NPY_ITER_WRITEMASKED -
Добавлено в версии 1.7.
Этот массив является маской для всех
writemaskedоперандов. Код использует флагwritemasked, который указывает, что будут записаны только элементы, где выбранный операнд ARRAYMASK равен True. Как правило, итератор этого не проверяет, это зависит от кода, выполняющего итерацию, который должен соблюдать это условие.При использовании флага
writemasked, если этот операнд буферизован, это меняет способ копирования данных из буфера в массив. Используется процедура маскированного копирования, которая копирует только элементы в буфере, для которыхwritemaskedвозвращает 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 const* 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равно нулю, используется размер буфера по умолчанию, в противном случае он определяет размер буфера. Рекомендуется использовать буферы, которые являются степенями двойки, такие как 4096 или 8192.Возвращает 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.NpyIter_Deallocateдолжен быть вызван для каждой копии.
-
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) -
Освобождает объект итератора и разрешает все необходимые записи.
Возвращает
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 const* multi_index) -
Изменяет указатель итератора на указанные индексы, на которые указывает
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, если вызывающий код должен обработать внутренний цикл с размерностью 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_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объектов, которые итерируются. Результат указывает наiter, поэтому вызывающий код не получает ссылок на описания.Этот указатель можно кэшировать перед циклом итерации, вызов
iternextне изменит его.
-
PyObject** NpyIter_GetOperandArray(NpyIter* iter) -
Возвращает указатель на
nopоперанды PyObjects, которые итерируются. Результат указывает наiter, поэтому вызывающий код не получает ссылок на PyObjects.
-
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, где для op_axes был передан NULL. Это для данных, упакованных непрерывно, но не обязательно в порядке 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) -
New in version 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.Типичная конструкция цикла следующая.
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.
-
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_ITER_DELAY_BUFALLOC), вызовите эту функцию, чтобы получить шаги, которые могут использоваться для выбора быстрой функции внутреннего цикла. Например, если шаг равен 0, это означает, что внутренний цикл всегда может загрузить своё значение в переменную один раз, а затем использовать переменную на протяжении всего цикла; или если шаг равен размеру элемента, можно использовать контигуальную версию для данного операнда.Эту функцию можно безопасно вызывать без удержания блокировки Python GIL.
Преобразование из предыдущих итераторов NumPy
Старый API итераторов включает функции, такие как PyArrayIter_Check, PyArray_Iter* и PyArray_ITER_*. Массив многократных итераторов включает PyArray_MultiIter*, PyArray_Broadcast и PyArray_RemoveSmallest. Новая конструкция итераторов заменяет всю эту функциональность одним объектом и связанным API. Одна из целей нового API заключается в том, что все используемые ранее итераторы могут быть заменены новым без значительных усилий. В версии 1.6 основным исключением из этого правила является итератор окрестности, у которого нет соответствующих функций в этом итераторе.
Вот таблица преобразования, какие функции использовать с новым итератором:
Функции итератора | |
| |
НЕ ПОДДЕРЖИВАЕТСЯ (Используйте поддержку нескольких операндов вместо этого.) | |
Это необходимо добавить в Python-экспозицию | |
Указатель на функцию из | |
Возвращаемое значение указателя на функцию | |
Функции многократной итерации | |
Указатель на функцию из | |
НЕ ПОДДЕРЖИВАЕТСЯ (всегда итерация с синхронизацией) | |
Возвращаемое значение указателя на функцию | |
Обрабатывается | |
Флаг итератора | |
Другие функции | |
Флаг итератора |
© 2005–2021 NumPy Developers
Licensed under the 3-clause BSD License.
https://numpy.org/doc/1.20/reference/c-api/iterator.html