I thought I knew all about Python Generators

The Unexpected Power of Python Generators

I thought I knew all about Python Generators

Python generators are like magic tricks for handling data. They help you work with large amounts of information without using up all your memory.

If you think you know everything about them, think again! I recently found a cool new way to use generators that totally surprised me.


What Are Python Generators?

Think of Python generators as smart vending machines for data. Instead of giving you all the items at once, they hand them out one by one.

You get a snack here, a snack there—one yield at a time.

Here’s a simple example:

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

When you use this generator, it’s like having a conveyor belt of numbers:

counter = count_up_to(5)
for number in counter:
    print(number)

And you get:

1
2
3
4
5

No need to store all the numbers at once—just a steady stream of digits.


What I Already Knew

Before my recent discovery, I thought I had generators all figured out. I knew how to make them, use them, and even had some tricks up my sleeve. Here’s what I was doing:

Simple Generator Function

A basic generator function that yields items one by one:

def simple_gen():
    yield 'a'
    yield 'b'
    yield 'c'

You can use this generator like this:

for char in simple_gen():
    print(char)

And you get:

a
b
c

Generator Expressions

I also used generator expressions for creating sequences on the fly:

squares = (x * x for x in range(5))

You can iterate over this generator like so:

for square in squares:
    print(square)

And you get:

0
1
4
9
16

Using next with Generators

Another cool trick I used was the next function, which lets you manually fetch the next item from a generator. Here’s an example:

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

counter = count_up_to(3)

print(next(counter))  # Outputs: 1
print(next(counter))  # Outputs: 2
print(next(counter))  # Outputs: 3
print(next(counter))  # Raises StopIteration

With next, you can grab items one at a time, and when the generator is done, it raises a StopIteration exception to let you know.

Generators were my go-to for handling large data. They helped me read big files line by line and deal with large queries without breaking a sweat.


What I Discovered

I was pretty surprised when I discovered a new way to use generators that made me feel like I was missing out on a great tool.

Nested Generator Function

Enter yield from—a way to use multiple generators together.

Here’s how it works:

def gen1():
    yield 1
    yield 2
    yield 3

def gen2():
    yield 'a'
    yield 'b'
    yield 'c'

def combined_gen():
    print("From First Generator")
    yield from gen1()

    print("From Second Generator")
    yield from gen2()

When you use combined_gen(), it’s like getting data from both gen1 and gen2:

for item in combined_gen():
    print(item)

And you get:

From First Generator
1
2
3
From Second Generator
a
b
c

Using next with Nested Generators

You can also use next to step through nested generators:

def gen1():
    yield 1
    yield 2
    yield 3

def gen2():
    yield 'a'
    yield 'b'
    yield 'c'

def combined_gen():
    print("From First Generator")
    yield from gen1()

    print("From Second Generator")
    yield from gen2()

gen = combined_gen()

print(next(gen))  # Prints: "From First Generator" & Outputs: 1
print(next(gen))  # Outputs: 2
print(next(gen))  # Outputs: 3
print(next(gen))  # Prints: "From Second Generator" & Outputs: a
print(next(gen))  # Outputs: b
print(next(gen))  # Outputs: c
print(next(counter))  # Raises StopIteration

In this example, yield from combines data from two generators, and using next lets you step through the output one item at a time.

It’s like having a remote control for your generator's data stream.


Why This Matters

Finding out about yield from felt like discovering a hidden feature on a tool you already use. It makes your code cleaner and easier to manage, especially when working with multiple data sources.

So, if you think you’ve mastered generators, give yield from a try. It might just make your coding life a lot easier and cooler.