Python Interactive Guide - Step 3 Functions (10) - Generator Functions
- This course, Python Interactive Guide, is designed to help you learn the basics of Python programming through hands-on, interactive examples.
- The “Style Guide” sections introduce clean coding practices, mainly based on PEP8.
- You can run and experiment with every code example.
Feel free to try things out - reloading the page will reset everything.
This is a continuation of “Step 3 Functions”.
3.9. Generator Functions
In this section, we’ll learn about generator functions, special functions that handle data efficiently.
3.9.1. What are Generator Functions?
In “2.2.3. Comprehensions”, we covered generator expressions.
Generator expressions return generator objects with the following properties:
- They are iterable (can be looped over)
- They are “one-time use” objects that yield values in sequence
- They generate values one at a time as needed, making them memory-efficient
Generator functions, which we’ll cover in this section, also return generator objects.
- A generator created by the function above executes code sequentially and returns the specified value when it reaches a
yieldstatement. This process repeats until the function ends. - When the function ends, value generation also ends.
- You can use the
next()function to get values from the generator one at a time.
- After all values are generated, calling
next()raises aStopIterationexception.
As you can see from the examples above, generators produced by generator functions have the following characteristics:
- When
next()is called, the code runs until it reaches the firstyieldstatement and returns that value - When
next()is called again, execution resumes from immediately after the previousyieldstatement, runs until the nextyieldstatement, and returns that value - In both cases, if there is no next
yieldstatement, the code runs to completion and then raises aStopIterationexception
In fact, a for loop works by “repeatedly calling next() and stopping when StopIteration is raised.”
Create a generator function called even_numbers that takes a parameter n and generates even numbers from 0 to n in sequence.
Sample Solution
Create a generator that produces the “Collatz sequence” which we also covered in the Recursive Functions section.
What is the Collatz Sequence?
The Collatz sequence is a sequence of numbers that starts with a positive integer n and follows these rules until reaching 1:
- If
nis 1: Stop the process - If
nis even: The next number isn / 2 - If
nis odd: The next number is3n + 1
By repeating this procedure, it’s conjectured that any starting number will eventually reach 1 (the “Collatz Conjecture”).
(Example: For n=6, the sequence is 6 → 3 → 10 → 5 → 16 → 8 → 4 → 2 → 1)
Problem
Implement a generator collatz_generator that takes a parameter n and generates the Collatz sequence in order.
Sample Solution
3.9.2. Infinite Generators
Using generator functions, you can create infinite sequences that couldn’t be represented with a list.
When using an infinite generator in a for loop, you need to break the loop under some condition:
3.9.3. Combining Multiple Generators (yield from)
The yield from syntax allows you to yield values sequentially from an iterable (such as a list or generator).
This enables the creation of generators that combine multiple generators in a concise way:
Without yield from, you would need verbose code like this:
yield from is not just a shorthand syntax—it also passes operations like send, throw, and close directly to the inner generator.
Create a generator function called combined_sequence using yield from that meets the following requirements:
- Take three different numerical lists as arguments
- Generate elements from each list in sequence
- Generate a separator value of -1 between each list
Sample Solution
3.9.4. Advanced Generator Features
So far, we’ve mainly used generators as “objects that produce values.” The following features allow you to send data to generators and control the flow of processing bidirectionally.
Sending Values to Generators (send method)
The send method allows you to send values to a generator.
The sent value is received as the return value of the yield expression:
The above statement performs two operations:
- When it is reached, it outputs “output_value” and pauses execution
- When the
sendmethod is called while paused at this statement, its argument is assigned to “variable” and code execution continues until the nextyieldstatement
To receive values using the send method, note the following:
- To use the
sendmethod, the generator must be paused at ayieldstatement.
Therefore, before usingsendfor the first time, you need to advance to ayieldstatement using thenext()function. - If the
next()function is used while paused at the above statement,Noneis assigned to “variable.”
Create a function stats() that produces a “generator that displays statistics for received values.”
- It receives numbers via the
sendmethod - Each time it receives a value, it displays the sum, count, and average of all values received so far
Sample Solution
Create a generator function error_monitor() that monitors logs.
- It receives strings via the
sendmethod - If “ERROR” appears 3 times in a row, return “ALERT”
- Otherwise, return
None
Sample Solution
Sending Exceptions to Generators (throw method)
While the send method sends regular data, the throw method allows you to send exceptions to a generator.
When you call the throw method, the specified exception is raised at the position of the yield statement where the generator last paused.
By sending exceptions, you can control the execution flow of a generator.
This is useful for error handling and resource cleanup in generators.
(Error handling will be explained in detail later)
Terminating a Generator (close method)
You can explicitly terminate a generator using the close method:
The close method is used when resources used by the generator need to be released.
Summary
In this section, we learned about generator functions.
-
Generator functions are special functions that use
yieldstatements to generate data one item at a time -
They are memory-efficient and can handle large or infinite data sequences effectively
-
Key features of generators:
- They are “one-time use” objects that yield values in sequence
- They use “lazy evaluation,” generating values one at a time as needed
- Values can be extracted using
forloops or thenext()function
-
Advanced features:
yield from: A concise way to yield values from other iterablessend()method: Enables bidirectional communication by sending values to generatorsthrow()method: Sends exceptions to generators for flow controlclose()method: Explicitly terminates a generator
Generator functions are powerful tools that can be used in various situations, such as processing large datasets and handling streams.
They’re especially useful when you need to handle large amounts of data while keeping memory usage low.