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
yield
statement. 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 aStopIteration
exception.
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 firstyield
statement and returns that value - When
next()
is called again, execution resumes from immediately after the previousyield
statement, runs until the nextyield
statement, and returns that value - In both cases, if there is no next
yield
statement, the code runs to completion and then raises aStopIteration
exception
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
n
is 1: Stop the process - If
n
is even: The next number isn / 2
- If
n
is 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
send
method is called while paused at this statement, its argument is assigned to “variable” and code execution continues until the nextyield
statement
To receive values using the send
method, note the following:
- To use the
send
method, the generator must be paused at ayield
statement.
Therefore, before usingsend
for the first time, you need to advance to ayield
statement using thenext()
function. - If the
next()
function is used while paused at the above statement,None
is assigned to “variable.”
Create a function stats()
that produces a “generator that displays statistics for received values.”
- It receives numbers via the
send
method - 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
send
method - 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
yield
statements 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
for
loops 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.