Iteration

Generators

yield creates an iterator that produces values on demand.

Calling a generator function returns an iterator. next() asks for one value and resumes the function until the next yield.

Source

def countdown(n):
    while n > 0:
        yield n
        n -= 1

numbers = countdown(3)
print(next(numbers))
print(next(numbers))

Output

3
2
PAUSED BETWEEN YIELDS · RESUMED BY NEXT()yieldyield
A generator's body is a timeline cut by yield gates: each next() advances to the next gate; locals survive the pause.

A for loop repeatedly calls next() for you. The loop stops when the generator is exhausted.

Source

for value in countdown(3):
    print(value)

Output

3
2
1

return builds the entire result before handing it back; yield produces values on demand. The list keeps its values for repeated use, while the generator is exhausted after one pass.

Source

def countdown_eager(n):
    result = []
    while n > 0:
        result.append(n)
        n -= 1
    return result

values = countdown_eager(3)
print(values)
print(values)

stream = countdown(3)
print(list(stream))
print(list(stream))

Output

[3, 2, 1]
[3, 2, 1]
[3, 2, 1]
[]

Every generator is an iterator. The same countdown written by hand needs __iter__ and __next__ and an explicit StopIteration. The generator function expresses the same protocol with one yield.

Source

class Countdown:
    def __init__(self, n):
        self.n = n

    def __iter__(self):
        return self

    def __next__(self):
        if self.n <= 0:
            raise StopIteration
        value = self.n
        self.n -= 1
        return value

print(list(Countdown(3)))

Output

[3, 2, 1]

Notes

See also

Run the complete example

Example code

Expected output

3
2
3
2
1
[3, 2, 1]
[3, 2, 1]
[3, 2, 1]
[]
[3, 2, 1]

Execution time appears here after you run the example.