It really helps to break things down by printing out what's going on along the way.

First, let's replace your whole loop with this:

i = 0
while not it.finished:
    i += 1
print i

It'll print 20, not 5. That's because you're doing a 5x4 iteration, not 5x1.

So, why is this even close to working? Well, let's look at the loop more carefully:

while not it.finished:
    print '>', it.operands[0], it[0]
    indices = np.arange(it[0],(it[0]+4), dtype=int)
    info = array.take(indices)
    info = info + 81
    it.operands[1][...]=info
    print '<', it.operands[1], it[1]

You'll see that the first five loops go through [0 4 8 12 16] five times, generating [[81 82 83 84]], then [[85 86 87 88]], etc. And then the next five loops do the same thing, and again and again.

This is also why your c_index solutions didn't work—because it.index is going to range from 0 to 19, and you don't have 20 of anything in it.operands[1].

If you did the multi_index right and ignored the columns, you could make this work… but still, you'd be doing a 5x4 iteration, just to repeat each step 4 times, instead of doing the 5x1 iteration you want.

Your it.operands[1][...]=info replaces the entire output with a 5x1 row each time through the loop. Generally, you shouldn't ever have to do anything to it.operands[1]—the whole point of nditer is that you just take care of each it[1], and the final it.operands[1] is the result.

Of course a 5x4 iteration over rows makes no sense. Either do a 5x4 iteration over individual values, or a 5x1 iteration over rows.

If you want the former, the easiest way to do it is to reshape the input array, then just iterate that:

it = np.nditer([array.reshape(5, -1), None],
               op_flags=[['readonly'],
                         ['readwrite','allocate']])
for a, b in it:
    b[...] = a + 81
return it.operands[1]

But of course that's silly—it's just a slower and more complicated way of writing:

return array+81

And it would be a bit silly to suggest that "the way to write your own reshape is to first call reshape, and then…"

So, you want to iterate over rows, right?

Let's simplify things a bit by getting rid of the allocate and explicitly creating a 5x4 array to start with:

outarray = np.zeros((5,4), dtype=array.dtype)
offset = np.array([0, 4, 8, 12, 16])
it = np.nditer([offset, outarray],
               flags=['reduce_ok'],
               op_flags=[['readonly'],
                         ['readwrite']],
               op_axes=[None, [0]],
               itershape=[5])

while not it.finished:
    indices = np.arange(it[0],(it[0]+4), dtype=int)
    info = array.take(indices)
    '''Just for fun, we'll perform an operation on data.\
       Let's shift it to 100'''
    info = info + 81
    it.operands[1][it.index][...]=info
    it.iternext()
return it.operands[1]

This is a bit of an abuse of nditer, but at least it does the right thing.

Since you're just doing a 1D iteration over the source and basically ignoring the second, there's really no good reason to use nditer here. If you need to do lockstep iteration over multiple arrays, for a, b in nditer([x, y], …) is cleaner than iterating over x and using the index to access y—just like for a, b in zip(x, y) outside of numpy. And if you need to iterate over multi-dimensional arrays, nditer is usually cleaner than the alternatives. But here, all you're really doing is iterating over [0, 4, 8, 16, 20], doing something with the result, and copying it into another array.

Also, as I mentioned in the comments, if you find yourself using iteration in numpy, you're usually doing something wrong. All of the speed benefits of numpy come from letting it execute the tight loops in native C/Fortran or lower-level vector operations. Once you're looping over arrays, you're effectively just doing slow Python numerics with a slightly nicer syntax:

import numpy as np
import timeit

def add10_numpy(array):
    return array + 10

def add10_nditer(array):
    it = np.nditer([array, None], [],
                   [['readonly'], ['writeonly', 'allocate']])
    for a, b in it:
        np.add(a, 10, b)
    return it.operands[1]

def add10_py(array):
    x, y = array.shape
    outarray = array.copy()
    for i in xrange(x):
        for j in xrange(y):
            outarray[i, j] = array[i, j] + 10
    return out array

myArray = np.arange(100000).reshape(250,-1)

for f in add10_numpy, add10_nditer, add10_py:
    print '%12s: %s' % (f.__name__, timeit.timeit(lambda: f(myArray), number=1))

On my system, this prints:

 add10_numpy: 0.000458002090454
add10_nditer: 0.292730093002
    add10_py: 0.127345085144

That shows you the cost of using nditer unnecessarily.

Answer from abarnert on Stack Overflow
🌐
NumPy
numpy.org › devdocs › reference › generated › numpy.nditer.html
numpy.nditer — NumPy v2.6.dev0 Manual
Try it in your browser! Here is how we might write an iter_add function, using the Python iterator protocol: ... >>> def iter_add_py(x, y, out=None): ... addop = np.add ... it = np.nditer([x, y, out], [], ... [['readonly'], ['readonly'], ['writeonly','allocate']]) ...
🌐
W3Schools
w3schools.com › python › numpy › numpy_array_iterating.asp
NumPy Array Iterating
NumPy does not change the data type of the element in-place (where the element is in array) so it needs some other space to perform this action, that extra space is called buffer, and in order to enable it in nditer() we pass flags=['buffered'].
People also ask

What is NumPy nditer used for?
numpy.nditer provides a configurable iterator for traversing array elements, tracking indexes, controlling order, updating operands, and iterating over multiple arrays.
🌐
pythonpool.com
pythonpool.com › home › numpy › numpy nditer(): multi-dimensional array iteration
Numpy nditer | Loop Through Numpy array - Python Pool
How do I modify an array with nditer?
Use an operand with readwrite access and understand buffering and writeback behavior before relying on in-place updates.
🌐
pythonpool.com
pythonpool.com › home › numpy › numpy nditer(): multi-dimensional array iteration
Numpy nditer | Loop Through Numpy array - Python Pool
How do I get indexes with nditer?
Pass the multi_index flag and read the iterator's multi_index property for a coordinate tuple during each iteration.
🌐
pythonpool.com
pythonpool.com › home › numpy › numpy nditer(): multi-dimensional array iteration
Numpy nditer | Loop Through Numpy array - Python Pool
🌐
GeeksforGeeks
geeksforgeeks.org › python › numpy-iterating-over-array
Numpy - Iterating Over Arrays - GeeksforGeeks
July 23, 2025 - It allows iteration in different orders and provides better control over the iteration process. ... import numpy as np # Using nditer arr = np.array([[1, 2], [3, 4]]) for element in np.nditer(arr): print(element)
🌐
NumPy
numpy.org › devdocs › reference › arrays.nditer.html
Iterating over arrays — NumPy v2.6.dev0 Manual
The most basic task that can be done with the nditer is to visit every element of an array. Each element is provided one by one using the standard Python iterator interface.
🌐
NumPy
numpy.org › doc › stable › reference › generated › numpy.nditer.html
numpy.nditer — NumPy v2.5 Manual
Try it in your browser! Here is how we might write an iter_add function, using the Python iterator protocol: ... >>> def iter_add_py(x, y, out=None): ... addop = np.add ... it = np.nditer([x, y, out], [], ... [['readonly'], ['readonly'], ['writeonly','allocate']]) ...
🌐
NumPy
numpy.org › doc › stable › reference › arrays.nditer.html
Iterating over arrays — NumPy v2.5 Manual
The most basic task that can be done with the nditer is to visit every element of an array. Each element is provided one by one using the standard Python iterator interface.
Top answer
1 of 1
13

It really helps to break things down by printing out what's going on along the way.

First, let's replace your whole loop with this:

i = 0
while not it.finished:
    i += 1
print i

It'll print 20, not 5. That's because you're doing a 5x4 iteration, not 5x1.

So, why is this even close to working? Well, let's look at the loop more carefully:

while not it.finished:
    print '>', it.operands[0], it[0]
    indices = np.arange(it[0],(it[0]+4), dtype=int)
    info = array.take(indices)
    info = info + 81
    it.operands[1][...]=info
    print '<', it.operands[1], it[1]

You'll see that the first five loops go through [0 4 8 12 16] five times, generating [[81 82 83 84]], then [[85 86 87 88]], etc. And then the next five loops do the same thing, and again and again.

This is also why your c_index solutions didn't work—because it.index is going to range from 0 to 19, and you don't have 20 of anything in it.operands[1].

If you did the multi_index right and ignored the columns, you could make this work… but still, you'd be doing a 5x4 iteration, just to repeat each step 4 times, instead of doing the 5x1 iteration you want.

Your it.operands[1][...]=info replaces the entire output with a 5x1 row each time through the loop. Generally, you shouldn't ever have to do anything to it.operands[1]—the whole point of nditer is that you just take care of each it[1], and the final it.operands[1] is the result.

Of course a 5x4 iteration over rows makes no sense. Either do a 5x4 iteration over individual values, or a 5x1 iteration over rows.

If you want the former, the easiest way to do it is to reshape the input array, then just iterate that:

it = np.nditer([array.reshape(5, -1), None],
               op_flags=[['readonly'],
                         ['readwrite','allocate']])
for a, b in it:
    b[...] = a + 81
return it.operands[1]

But of course that's silly—it's just a slower and more complicated way of writing:

return array+81

And it would be a bit silly to suggest that "the way to write your own reshape is to first call reshape, and then…"

So, you want to iterate over rows, right?

Let's simplify things a bit by getting rid of the allocate and explicitly creating a 5x4 array to start with:

outarray = np.zeros((5,4), dtype=array.dtype)
offset = np.array([0, 4, 8, 12, 16])
it = np.nditer([offset, outarray],
               flags=['reduce_ok'],
               op_flags=[['readonly'],
                         ['readwrite']],
               op_axes=[None, [0]],
               itershape=[5])

while not it.finished:
    indices = np.arange(it[0],(it[0]+4), dtype=int)
    info = array.take(indices)
    '''Just for fun, we'll perform an operation on data.\
       Let's shift it to 100'''
    info = info + 81
    it.operands[1][it.index][...]=info
    it.iternext()
return it.operands[1]

This is a bit of an abuse of nditer, but at least it does the right thing.

Since you're just doing a 1D iteration over the source and basically ignoring the second, there's really no good reason to use nditer here. If you need to do lockstep iteration over multiple arrays, for a, b in nditer([x, y], …) is cleaner than iterating over x and using the index to access y—just like for a, b in zip(x, y) outside of numpy. And if you need to iterate over multi-dimensional arrays, nditer is usually cleaner than the alternatives. But here, all you're really doing is iterating over [0, 4, 8, 16, 20], doing something with the result, and copying it into another array.

Also, as I mentioned in the comments, if you find yourself using iteration in numpy, you're usually doing something wrong. All of the speed benefits of numpy come from letting it execute the tight loops in native C/Fortran or lower-level vector operations. Once you're looping over arrays, you're effectively just doing slow Python numerics with a slightly nicer syntax:

import numpy as np
import timeit

def add10_numpy(array):
    return array + 10

def add10_nditer(array):
    it = np.nditer([array, None], [],
                   [['readonly'], ['writeonly', 'allocate']])
    for a, b in it:
        np.add(a, 10, b)
    return it.operands[1]

def add10_py(array):
    x, y = array.shape
    outarray = array.copy()
    for i in xrange(x):
        for j in xrange(y):
            outarray[i, j] = array[i, j] + 10
    return out array

myArray = np.arange(100000).reshape(250,-1)

for f in add10_numpy, add10_nditer, add10_py:
    print '%12s: %s' % (f.__name__, timeit.timeit(lambda: f(myArray), number=1))

On my system, this prints:

 add10_numpy: 0.000458002090454
add10_nditer: 0.292730093002
    add10_py: 0.127345085144

That shows you the cost of using nditer unnecessarily.

Find elsewhere
🌐
Analytics Vidhya
analyticsvidhya.com › home › iteration in python – enumerate(), item(), np.nditer(), iterrows()
Iteration in Python | enumerate(), item(), np.nditer(), iterrows()
October 22, 2024 - for x in np.nditer(my_array) : Below we are writing a for loop that iterates over all elements in np_height and prints out “x inches” for each element, where x is the value in the array.
🌐
TutorialsPoint
tutorialspoint.com › numpy › numpy_iterating_over_array.htm
NumPy - Iterating Over Array
The nditer() function in NumPy provides an efficient multidimensional iterator object that can be used to iterate over elements of arrays. It uses Python's standard iterator interface to visit each element of an array.
🌐
Python Pool
pythonpool.com › home › numpy › numpy nditer(): multi-dimensional array iteration
Numpy nditer | Loop Through Numpy array - Python Pool
July 13, 2026 - Use NumPy nditer() for controlled array iteration, multi_index, readwrite updates, buffered operands, order, and multiple arrays.
🌐
Kaggle
kaggle.com › general › 521858
Numpy Arrays Iterating | Kaggle
# Create 3D array arr1_3d = np.array([ ... k : print(h) ... The nditer() function simplifies iteration over NumPy arrays of any dimension, allowing us to access each element in a single loop....
🌐
NumPy
numpy.org › doc › 2.1 › reference › arrays.nditer.html
Iterating over arrays — NumPy v2.1 Manual
The most basic task that can be done with the nditer is to visit every element of an array. Each element is provided one by one using the standard Python iterator interface.
🌐
Scaler
scaler.com › home › topics › numpy › numpy iterating over array
NumPy Iterating Over Array - Scaler Topics - Scaler Topics
September 9, 2022 - Numpy.nditer is an iterator object in the NumPy package. It is a multidimensional iterator object that can efficiently traverse an array. The standard Iterator interface in Python is used to visit each element of an array.
🌐
GitHub
github.com › davrot › pytutorial › blob › main › numpy › nditer › README.md
pytutorial/numpy/nditer/README.md at main · davrot/pytutorial · GitHub
Check whether iterations are left, and perform a single internal iteration without returning the result. Used in the C-style pattern do-while pattern. For an example, see nditer.
Author: davrot
🌐
NumPy
numpy.org › doc › 2.1 › reference › generated › numpy.nditer.html
numpy.nditer — NumPy v2.1 Manual
class numpy.nditer(op, flags=None, op_flags=None, op_dtypes=None, order='K', casting='safe', op_axes=None, itershape=None, buffersize=0)[source]# Efficient multi-dimensional iterator object to iterate over arrays. To get started using this object, see the introductory guide to array iteration.
🌐
NumPy
numpy.org › doc › 2.2 › reference › arrays.nditer.html
Iterating over arrays — NumPy v2.2 Manual
The most basic task that can be done with the nditer is to visit every element of an array. Each element is provided one by one using the standard Python iterator interface.
🌐
Medium
medium.com › @keycomputereducation › numpy-tutorial-iterate-over-array-c2f7db6dc843
Numpy tutorial — Iterate Over Array | by Key computer Education | Medium
February 1, 2022 - Numpy tutorial — Iterate Over Array Iterate over array means accessing each element in each row. In Numpy, nditer() function helps to iterate. Function nditer() takes Numpy array as an argument and …
🌐
NumPy
numpy.org › doc › 2.0 › reference › arrays.nditer.html
Iterating over arrays — NumPy v2.0 Manual
The most basic task that can be done with the nditer is to visit every element of an array. Each element is provided one by one using the standard Python iterator interface.
🌐
Jiffyclub
jiffyclub.github.io › numpy › reference › generated › numpy.nditer.html
numpy.nditer — NumPy v1.12 Manual
The native Python approach is better in most cases, but if you need the iterator’s coordinates or index, use the C-style pattern. ... def iter_add_py(x, y, out=None): addop = np.add it = np.nditer([x, y, out], [], [['readonly'], ['readonly'], ['writeonly','allocate']]) for (a, b, c) in it: addop(a, b, out=c) return it.operands[2]
🌐
Learning Actors
learningactors.com › home › blog › iteration in python – enumerate(), item(), np.nditer(), iterrows()
Iteration in Python – enumerate(), item(), np.nditer(), iterrows() - Learning Actors
February 18, 2021 - for x in np.nditer(my_array) : Below we are writing a for loop that iterates over all elements in np_height and prints out “x inches” for each element, where x is the value in the array.