Iteration Strategies
Understanding Generator Iteration
Generator iteration can be complex, with multiple strategies for resetting and reusing generators. Unlike lists, generators are consumed after a single iteration, requiring specific techniques for reset.
Basic Iteration Methods
Method 1: Recreating the Generator
def number_generator():
yield from range(5)
## First iteration
gen1 = number_generator()
print(list(gen1)) ## [0, 1, 2, 3, 4]
## Second iteration requires recreating generator
gen2 = number_generator()
print(list(gen2)) ## [0, 1, 2, 3, 4]
import itertools
def number_generator():
yield from range(5)
## Create multiple independent iterators
gen1, gen2 = itertools.tee(number_generator())
print(list(gen1)) ## [0, 1, 2, 3, 4]
print(list(gen2)) ## [0, 1, 2, 3, 4]
Advanced Iteration Techniques
Caching Generator Results
def cached_generator():
cache = []
def generator():
for item in range(5):
cache.append(item)
yield item
return generator, cache
gen_func, result_cache = cached_generator()
gen = gen_func()
print(list(gen)) ## [0, 1, 2, 3, 4]
print(result_cache) ## [0, 1, 2, 3, 4]
Iteration Strategy Comparison
Strategy |
Memory Efficiency |
Complexity |
Reusability |
Recreating Generator |
High |
Low |
Moderate |
itertools.tee() |
Moderate |
Medium |
High |
Caching |
Low |
High |
High |
Generator Iteration Flow
graph LR
A[Generator Creation] --> B{Iteration Started}
B --> |First Pass| C[Values Consumed]
C --> |Reset Needed| D[Recreate Generator]
D --> B
Best Practices
- Prefer recreation for simple generators
- Use
itertools.tee()
for parallel iterations
- Implement custom caching for complex scenarios
At LabEx, we recommend choosing iteration strategies based on:
- Memory constraints
- Computational complexity
- Specific use case requirements
Error Handling in Iterations
def safe_generator():
try:
yield from range(5)
except GeneratorExit:
print("Generator closed")
gen = safe_generator()
list(gen) ## Normal iteration
gen.close() ## Explicit closure
Advanced Technique: Generator Wrapping
def generator_wrapper(gen_func):
def wrapper(*args, **kwargs):
return gen_func(*args, **kwargs)
return wrapper
@generator_wrapper
def repeatable_generator():
yield from range(3)