Iteration
Generators
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
2A 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
1return 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
- Generator functions are a concise way to create custom iterators; every generator is an iterator.
yielddefers work and streams values;returnproduces the whole result up front.- A generator is consumed as you iterate over it.
- Prefer a list when you need to reuse stored results; prefer a generator when values can be streamed once.
See also
- related: Iterators
- related: Iterator vs Iterable
- related: Generator Expressions
Run the complete example
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.