Search code examples
pythoniteratorgenerator

Understanding iterator default value


I'm having trouble understanding why the third next(w) executes, and StopIteration exception get raised at the next one and not at the third.

From my understanding, next(w) should raise StopIteration whenever any of its expressions are exhausted, and it happens whenever next(y, 'b') reaches the default value, which is 'b'.

Why does the iterator returns the default value twice?

x = iter(range(3))
y = iter(range(3))
w = ([next(y, "a"), next(y, "b")] for z in x)
try:
    print(next(w)) # -> prints [0, 1]
    print(next(w)) # -> prints [2, 'b']
    print(next(w)) # -> prints ['a', 'b']
    print(next(w)) # raise StopIteration
    print(next(w))
except:
    print("7") # -> prints '7'

Solution

  • Why does the iterator returns the default value twice?

    The iterator returns the default value as many times at it is called, not only twice. The problem occurs because you defined x and w as follows:

    x = iter(range(3))
    y = iter(range(3))
    w = ([next(y, "a"), next(y, "b")] for z in x)
    

    Your w list has 3 entries (it iterates over the 3 elements in x), and when you call next(w) a fourth time, it throws an exception. Try setting x = iter(range(5)), and you will see that you can now call print(next(w)) 5 times. The inner next calls will return the default values as many times as called.

    To confirm this, just output w after creating it, so you can see its contents:

    x = iter(range(3))
    y = iter(range(3))
    w = ([next(y, "a"), next(y, "b")] for z in x)
    list(w)
    
    > [[0, 1], [2, 'b'], ['a', 'b']]