What is a Generator ?
Why Use Generators ?
Efficient: Instead of holding all values in memory (like lists), generators produce them one at a time.
Faster when working with large data as they don’t pre-compute all values.
Lazy Evaluation: Values are computed only when required.
How Generators Work
yield vs return
| Keyword | Description |
|---|---|
| yield: | Pauses the function and saves its state. Execution resumes from the same point on the next call. |
| return: | Ends the function execution and sends back a result. |
Generator Object:
When a generator function is called, it doesn’t execute immediately. Instead, it returns a generator object.
Use next() to get the next value from the generator or loop through it with a for loop.
Generator Syntax: Creating a Generator
def generator_function():
yield value
Example 1: Simple Generator
def simple_generator():
yield 1
yield 2
yield 3
gen = simple_generator() print(next(gen)) # Output: 1 print(next(gen)) # Output: 2 print(next(gen)) # Output: 3
Real-Life Analogy
Imagine a vending machine:Instead of giving you all the snacks at once, it gives you one snack when you press a button (lazy evaluation).
Each button press resumes from where it left off (maintaining state).
Examples of Generators in Python
1. Basic Generator
def count_up_to(n):
count = 1
while count <= n:
yield count
count += 1
for number in count_up_to(5):
print(number)
Output:
1
2
3
4
5
2. Infinite Generator
Generators can produce infinite sequences.
def infinite_numbers():
num = 0
while True:
yield num
num += 1
gen = infinite_numbers()
for _ in range(5):
print(next(gen)) # Output: 0, 1, 2, 3, 4
Real-Life Use Case: Generating unique IDs or timestamps.
3. Fibonacci Sequencedef fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
fib = fibonacci()
for _ in range(10):
print(next(fib))
Output:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34
4. Filtering Data with Generators Generators can filter large datasets efficiently.
def even_numbers(sequence):
for number in sequence:
if number % 2 == 0:
yield number
numbers = range(10)
for even in even_numbers(numbers):
print(even)
Output:
0, 2, 4, 6, 8
Using Generator Expressions
A generator expression is a compact way to create a generator, similar to list comprehensions but with parentheses.
Examplesquared = (x ** 2 for x in range(5)) print(next(squared)) # Output: 0 print(next(squared)) # Output: 1
Compare:
List comprehension: [x ** 2 for x in range(5)] creates the entire list in memory.
Generator expression: (x ** 2 for x in range(5)) computes one value at a time.
Advantages of Generators
Memory Usage:
Lists store all elements in memory.
Generators compute elements on demand, making them suitable for large or infinite sequences.
import sys list_nums = [x ** 2 for x in range(1000)] gen_nums = (x ** 2 for x in range(1000)) print(sys.getsizeof(list_nums)) # Output: Memory size of list print(sys.getsizeof(gen_nums)) # Output: Memory size of generator
Key Methods for Generator
| Method | Description |
|---|---|
| next(generator) | Retrieves the next value from the generator. |
| StopIteration | Raised when the generator has no more values to produce. |
| for loop | Automatically handles the StopIteration. |
Real-Life Applications
1. Processing Large Files Generators are perfect for reading large files line by line without loading the entire file into memory.
def read_large_file(file_path):
with open(file_path, 'r') as file:
for line in file:
yield line.strip()
for line in read_large_file("large_file.txt"):
print(line)
2. Streaming Data Handle live data streams like sensor readings or API responses.
import time
def live_sensor_data():
while True:
yield f"Sensor Reading at {time.time()}"
time.sleep(1)
for reading in live_sensor_data():
print(reading)
33. Pipelining Use multiple generators together to process data step-by-step.
def numbers():
for i in range(10):
yield i
def square_numbers(nums):
for n in nums:
yield n ** 2
pipeline = square_numbers(numbers())
for value in pipeline:
print(value)
Comparing Generators with Iterators
| Feature | Generator | Iterator |
|---|---|---|
| Definition | Created using yield or expressions | Created using custom __iter__() and __next__() methods |
| State Maintenance | Automatic | Manual |
| Ease of Use | Easy | Requires more boilerplate code |
Key Takeaways
Generators are ideal for processing large or infinite sequences efficiently.
Use yield to pause and resume execution
They shine in scenarios like:
Iterating over large datasets (e.g., files, APIs).
Producing infinite or dynamic sequences.
Creating pipelines for data transformation.