Iterators & Generators

Produce values one at a time, lazily, with yield.

Syntaxdef gen(): yield value

An iterator produces items one at a time. A generator is the easiest way to make one: write a function that uses yield instead of return.

Why generators?

They are lazy — values are produced only as needed, so you can work with huge or even infinite sequences without storing them all in memory.

Example

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

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

# A generator expression:
squares = (x * x for x in range(4))
print(list(squares))

# Output:
# 3
# 2
# 1
# [0, 1, 4, 9]

When to use it

  • A log reader uses a generator to stream lines from a multi-gigabyte file without loading it all into memory.
  • A data pipeline yields transformed records one at a time so memory stays constant regardless of dataset size.
  • An infinite counter generator produces unique IDs on demand without pre-generating a list.

More examples

Simple generator function

Defines a generator that yields values one at a time instead of returning a list.

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

for val in countdown(5):
    print(val, end=' ')
# Output: 5 4 3 2 1

Generator for large file reading

Yields lines from a file one by one, keeping memory usage constant for arbitrarily large files.

Example · python
def read_lines(filepath):
    with open(filepath) as f:
        for line in f:
            yield line.rstrip()

for line in read_lines('notes.txt'):
    print(line)

Generator expression

Creates a lazy generator expression (like a list comprehension with parentheses) that computes values on demand.

Example · python
numbers = range(1, 1_000_001)
squares_gen = (n ** 2 for n in numbers if n % 2 == 0)

print(next(squares_gen))   # 4
print(next(squares_gen))   # 16
print(sum(squares_gen))    # rest of the evens squared

Discussion

  • Be the first to comment on this lesson.