Advanced Patterns
Generator Composition and Chaining
Combining Generators
def generator1():
yield from range(3)
def generator2():
yield from range(3, 6)
## Chaining generators
combined = itertools.chain(generator1(), generator2())
print(list(combined)) ## [0, 1, 2, 3, 4, 5]
Infinite Generators
Creating Endless Sequences
def infinite_counter(start=0):
while True:
yield start
start += 1
## Limiting infinite generator
limited_counter = itertools.islice(infinite_counter(), 5)
print(list(limited_counter)) ## [0, 1, 2, 3, 4]
Mapping and Filtering
def transform_generator(source_gen, map_func, filter_func=None):
for item in source_gen:
if filter_func is None or filter_func(item):
yield map_func(item)
## Example usage
numbers = range(10)
squared_evens = transform_generator(
numbers,
map_func=lambda x: x**2,
filter_func=lambda x: x % 2 == 0
)
print(list(squared_evens)) ## [0, 4, 16, 36, 64]
Generator State Management
Stateful Generators
def stateful_generator():
state = 0
while True:
increment = yield state
if increment is not None:
state += increment
else:
state += 1
## Using send() method
gen = stateful_generator()
print(next(gen)) ## 0
print(gen.send(5)) ## 5
print(next(gen)) ## 6
Advanced Generator Patterns
Pattern |
Description |
Use Case |
Coroutines |
Two-way communication |
Complex state management |
Pipeline Generators |
Data processing |
ETL operations |
Recursive Generators |
Nested iterations |
Tree traversal |
Generator Execution Flow
graph TD
A[Generator Creation] --> B{Iteration Started}
B --> C[Yield Current Value]
C --> D{More Items?}
D --> |Yes| E[Pause and Wait]
D --> |No| F[Generator Exhausted]
E --> C
- Use
yield from
for nested generators
- Minimize state storage
- Leverage built-in itertools functions
- Avoid unnecessary list conversions
Complex Example: Data Processing Pipeline
def read_data(filename):
with open(filename, 'r') as file:
for line in file:
yield line.strip()
def parse_data(data_gen):
for line in data_gen:
yield line.split(',')
def filter_data(data_gen, condition):
for item in data_gen:
if condition(item):
yield item
## Composing generators
filename = 'data.csv'
processed_data = filter_data(
parse_data(read_data(filename)),
condition=lambda x: len(x) > 2
)
Error Handling and Generator Lifecycle
def safe_generator(source_gen):
try:
for item in source_gen:
yield item
except Exception as e:
print(f"Generator error: {e}")
By mastering these advanced generator patterns, you'll be able to write more sophisticated and efficient Python code, leveraging the full power of generator comprehensions and iterators.