Iterators and Generators in Python
1. Iterators in Python
An iterator is an object that can be iterated (looped) upon. It follows two key methods:
Example: Creating an Iterator
class MyNumbers:
def __init__(self):
self.num = 1
def __iter__(self):
return self # Returning the iterator object itself
def __next__(self):
if self.num <= 5:
current = self.num
self.num += 1
return current
else:
raise StopIteration # Stop when numbers exceed 5
# Using the iterator
numbers = MyNumbers()
for number in numbers:
print(number)
Output
1
2
3
4
5
In this example:
When to Use Iterators?
1. Custom Iterable Objects
class LinkedListIterator:
def __init__(self, head):
self.current = head
def __iter__(self):
return self
def __next__(self):
if self.current:
data = self.current.data
self.current = self.current.next
return data
else:
raise StopIteration
# Assuming we have a LinkedList class with head node
# linked_list = LinkedList([1, 2, 3])
# for item in linked_list: # Using the iterator to loop over the nodes
# print(item)
Usage:
2. Database Query Results
class DatabaseIterator:
def __init__(self, cursor):
self.cursor = cursor
def __iter__(self):
return self
def __next__(self):
row = self.cursor.fetchone()
if row:
return row
else:
raise StopIteration
# Usage: Fetch rows from a cursor one by one without loading everything into memory.
# for row in DatabaseIterator(cursor):
# print(row)
Usage:
2. Generators in Python
A generator is a simpler way to create iterators using the yield keyword.
How Generators Work:
Example: Creating a Generator
def my_generator():
num = 1
while num <= 5:
yield num # Yield pauses the function and returns a value
num += 1
# Using the generator
for number in my_generator():
print(number)
Output
1
2
3
4
5
In this example:
When to Use Generators?
1. Reading Large Files Line-by-Line
def read_large_file(filename):
with open(filename) as file:
for line in file:
yield line.strip()
# Usage
for line in read_large_file('large_text_file.txt'):
print(line) # Process each line without loading entire file into memory
Usage:
2. Infinite Data Streams (Lazy Evaluation)
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
# Usage
fib = fibonacci()
for _ in range(10):
print(next(fib)) # Prints the first 10 Fibonacci numbers
3. Chunking Data for Batch Processing
def chunk_data(data, chunk_size):
for i in range(0, len(data), chunk_size):
yield data[i:i + chunk_size]
# Usage
data = [1, 2, 3, 4, 5, 6, 7, 8]
for chunk in chunk_data(data, 3):
print(chunk) # Output: [1, 2, 3], [4, 5, 6], [7, 8]
Usage:
4. Web Scraping Pagination
def url_generator(base_url, pages):
for page in range(1, pages + 1):
yield f"{base_url}?page={page}"
# Usage
for url in url_generator('https://example.com/data', 5):
print(url)
Usage:
5. Pipeline Data Processing
def generate_numbers():
for i in range(1, 6):
yield i
def square_numbers(numbers):
for number in numbers:
yield number * number
# Usage: Chain two generators together
squared_numbers = square_numbers(generate_numbers())
for num in squared_numbers:
print(num) # Output: 1, 4, 9, 16, 25
Usage:
Difference Between Iterators and Generators
When to Use Iterators vs Generators
In summary, iterators are great when you need custom control over how data is accessed, such as with custom data structures or database queries. On the other hand, generators shine in scenarios involving large datasets, real-time streaming, or infinite data streams because they are more memory-efficient and simpler to implement.
For more in-depth technical insights and articles, feel free to explore:
"Have you explored this topic? Share your insights or drop your questions in the comments!"
HubSpot Certified Expert | Boosting Revenue by 20-50% Through Pipeline Optimization | Helping Sales Teams Close Faster
11momastering python is like riding a bike—once you get it, you'll glide! what’s your favorite part about coding?