Iterators and Generators
Let’s explore Iterators and Generators in Python 🌀⚡—with clear explanations, step-by-step code, and practice questions (with solutions)!
🧩 What is an Iterator?
An iterator is an object that allows you to traverse through all the elements of a collection (like a list, tuple, or string), one element at a time.
- Iterable: Any object you can loop over (e.g., list, tuple, set, string).
- Iterator: An object with two methods:
__iter__()and__next__(). It remembers its position during iteration.
How to Use Iterators
numbers = [1, 2, 3]
it = iter(numbers) # Get iterator from iterable
print(next(it)) # 1
print(next(it)) # 2
print(next(it)) # 3
# print(next(it)) # Raises StopIteration error if no more itemsiter() gets the iterator; next() gets the next item until the end is reached.1
⚙️ How Iterators Work in Loops
A for loop in Python automatically creates an iterator from the iterable and uses next() to get each item until StopIteration is raised.2
for num in numbers:
print(num)⚡ What is a Generator?
A generator is a special type of iterator, created by a function with the yield keyword.
- Generator function: Uses
yieldinstead ofreturn. - Generator object: Returned by calling a generator function; you can iterate over it just like any other iterator.
Example: Generator Function
def countdown(n):
while n > 0:
yield n
n -= 1
gen = countdown(3)
print(next(gen)) # 3
print(next(gen)) # 2
print(next(gen)) # 1
# print(next(gen)) # StopIteration errorEach call to next() resumes where the function last yielded.1
🔄 Difference: Iterator vs Generator
| Feature | Iterator | Generator |
|---|---|---|
| How created | From any iterable (using iter()) | From a function with yield |
| Memory usage | May store all data in memory | Generates values on the fly (lazy) |
| Syntax | Class with __iter__/__next__ | Function with yield |
| Example | iter([^1][^3][^2]) | def gen(): yield ... |
🧠 Generator Expressions
Like list comprehensions, but use () and generate items one by one.
squares = (x*x for x in range(5))
for num in squares:
print(num) # 0 1 4 9 16Efficient for large data—doesn’t build the whole list in memory!3
📝 Practice Questions
1️⃣ Create an iterator for a list and print all values using next().
Solution
lst = [10, 20, 30]
it = iter(lst)
print(next(it)) # 10
print(next(it)) # 20
print(next(it)) # 302️⃣ Write a generator function that yields even numbers up to 10.
Solution
def even_numbers():
n = 0
while n <= 10:
yield n
n += 2
for num in even_numbers():
print(num) # 0 2 4 6 8 103️⃣ Use a generator expression to print cubes of numbers 1 to 5.
Solution
cubes = (x**3 for x in range(1, 6))
for c in cubes:
print(c) # 1 8 27 64 1254️⃣ What happens if you call next() on an iterator after it’s exhausted?
Answer:
You get a StopIteration error.
⭐ Key Points
- Iterators: Objects that allow you to traverse through all elements, one at a time, using
iter()andnext(). - Generators: Special iterators created with functions using
yield. More memory-efficient for large data. - Generator expressions: Like list comprehensions but lazy (produce items one by one, not all at once).
forloops: Automatically use iterators behind the scenes.
Practice using iterators and generators—they’re powerful tools for efficient Python code! 🚀
References:
- Python-Cheatsheet-2024.pdf (Iterator and Generator section)1
- Learning_Python.pdf (Iteration, for loops, generator expressions)3
- itpacs_cafiero.pdf (Iterables, enumerate, behind-the-scenes of iteration)2