A generator function uses yield instead of return. Each yield gives back one value and pauses the function. The next time a value is needed, the function continues from where it stopped.
The program
def countdown(n): while n > 0: yield n n -= 1 for number in countdown(5): print(number, end=" ") print("Lift off!")
5 4 3 2 1 Lift off!
How it works
- Calling
countdown(5)does not run the body yet. It returns a generator object. - The
forloop asks the generator for values. Each time, the body runs until the nextyield, then pauses with all its local variables kept. - When the function body ends, the generator is finished and the loop stops.
Step by step with next()
next() asks for one value at a time, which shows the pausing clearly. After the last value, next() raises StopIteration:
def countdown(n): print("starting") while n > 0: yield n n -= 1 print("done") gen = countdown(2) print(next(gen)) print(next(gen)) try: next(gen) except StopIteration: print("no more values")
starting 2 1 done no more values
An endless generator
Because values are produced only when asked for, a generator can go on forever without using more memory. itertools.islice takes the first few values:
from itertools import islice def fibonacci(): a, b = 0, 1 while True: yield a a, b = b, a + b print(list(islice(fibonacci(), 10)))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
A list of all Fibonacci numbers could never be built. The generator holds only two numbers, a and b, at any time.