What are Generators?

Generators are functions that return an iterator. They use yield instead of return and produce values one at a time, making them memory efficient.

Simple Generator

Create a generator function:

def count_up_to(max):
    count = 1
    while count <= max:
        yield count
        count += 1

# Use the generator
for num in count_up_to(5):
    print(num)  # 1, 2, 3, 4, 5

Generator vs List

Generators are memory efficient:

# List - stores all values
def squares_list(n):
    return [x**2 for x in range(n)]

# Generator - produces on demand
def squares_gen(n):
    for x in range(n):
        yield x**2

# Generator expression
squares = (x**2 for x in range(10))

Using next()

Manually iterate through generator:

gen = count_up_to(3)
print(next(gen))  # 1
print(next(gen))  # 2
print(next(gen))  # 3
# print(next(gen))  # StopIteration

Generator Expressions

Similar to list comprehensions:

# List comprehension
squares_list = [x**2 for x in range(10)]

# Generator expression
squares_gen = (x**2 for x in range(10))

# More memory efficient
print(sum(squares_gen))  # 285

Why Use Generators?

  • Memory efficient: Don't store all values
  • Lazy evaluation: Values computed when needed
  • Infinite sequences: Can generate infinite data
  • Pipeline processing: Chain generators together

Best Practices

  • Use for large datasets: When memory is a concern
  • Use generator expressions: For simple transformations
  • Don't reuse generators: They're one-time use
  • Consider itertools: For complex generator patterns

Next Steps

Learn about iterators and comprehensions.