Iterators in Python
Iterators in Python
An iterator in Python is an object that is used to iterate over iterable objects like lists, tuples, dictionaries, and sets. An iterator can be thought of as a pointer to a container’s elements.
To create an iterator, you use the iter() function. To get the next element from the iterator, you use the next() function. When there are no more elements, the next() function raises a StopIteration error.
Example
Let’s use a list as an example to see how an iterator works.
Python
# Create a list
my_list = ['apple', 'banana', 'cherry']
# Create an iterator from the list
my_iterator = iter(my_list)
# Get the first element
print(next(my_iterator))
# Get the second element
print(next(my_iterator))
# Get the third element
print(next(my_iterator))
# Trying to get the next element will raise a StopIteration error
try:
print(next(my_iterator))
except StopIteration:
print("No more elements in the iterator.")
Output:
apple
banana
cherry
No more elements in the iterator.
In this example, the my_iterator object keeps track of the current position. Each call to next() moves the iterator to the next element in the list.
How a for loop works with an iterator
The for loop in Python is a convenient way to handle iteration. Under the hood, a for loop automatically creates an iterator for the iterable and calls next() on it until a StopIteration error is raised.
The following for loop:
Python
for fruit in my_list:
print(fruit)
is equivalent to:
Python
# Get an iterator
my_iterator = iter(my_list)
# Loop indefinitely
while True:
try:
# Get the next item
fruit = next(my_iterator)
# Print the item
print(fruit)
except StopIteration:
# Break the loop when the iterator is exhausted
break
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, dictionary, etc.) one by one. It remembers its state during iteration.
Key Concepts
- Iterable: An object that can return an iterator (lists, tuples, strings, etc.)
- Iterator: An object that implements
__iter__()and__next__()methods
Basic Examples
Example 1: Basic Iterator using iter() and next()
python
# Create a list (iterable) fruits = ["apple", "banana", "cherry"] # Get an iterator fruit_iterator = iter(fruits) # Get elements one by one print(next(fruit_iterator)) # Output: apple print(next(fruit_iterator)) # Output: banana print(next(fruit_iterator)) # Output: cherry # This will raise StopIteration error (no more items) # print(next(fruit_iterator))
Example 2: Using Iterator in a Loop
python
numbers = [1, 2, 3, 4, 5]
num_iterator = iter(numbers)
while True:
try:
number = next(num_iterator)
print(number)
except StopIteration:
break
# Output: 1 2 3 4 5
Example 3: Strings are Iterable too!
python
message = "Hello" char_iterator = iter(message) print(next(char_iterator)) # Output: H print(next(char_iterator)) # Output: e print(next(char_iterator)) # Output: l print(next(char_iterator)) # Output: l print(next(char_iterator)) # Output: o
How for-loops Actually Work
Behind the scenes, this:
python
for item in my_list:
print(item)
Is equivalent to:
python
iterator = iter(my_list)
while True:
try:
item = next(iterator)
print(item)
except StopIteration:
break
Creating Your Own Iterator
Example 4: Simple Custom Iterator
python
class CountDown:
def __init__(self, start):
self.current = start
def __iter__(self):
return self
def __next__(self):
if self.current <= 0:
raise StopIteration
else:
self.current -= 1
return self.current + 1
# Using our custom iterator
counter = CountDown(3)
for number in counter:
print(number)
# Output: 3 2 1
Example 5: Number Range Iterator
python
class NumberRange:
def __init__(self, start, end):
self.current = start
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.current > self.end:
raise StopIteration
else:
self.current += 1
return self.current - 1
# Create and use iterator
num_range = NumberRange(1, 5)
for num in num_range:
print(num)
# Output: 1 2 3 4 5
Practical Examples
Example 6: File Reading with Iterator
python
# Files are iterators too!
with open('example.txt', 'w') as f:
f.write("Line 1\nLine 2\nLine 3")
# Read file line by line using iterator
with open('example.txt', 'r') as file:
for line in file: # This uses iterator!
print(line.strip())
# Output: Line 1, Line 2, Line 3
Example 7: Dictionary Iterator
python
student = {"name": "Alice", "age": 20, "grade": "A"}
# Iterate through keys
for key in student:
print(key)
# Output: name, age, grade
# Iterate through values
for value in student.values():
print(value)
# Output: Alice, 20, A
# Iterate through key-value pairs
for key, value in student.items():
print(f"{key}: {value}")
# Output: name: Alice, age: 20, grade: A
Built-in Functions that Use Iterators
Example 8: Using enumerate()
python
fruits = ["apple", "banana", "cherry"]
for index, fruit in enumerate(fruits):
print(f"Index {index}: {fruit}")
# Output: Index 0: apple, Index 1: banana, Index 2: cherry
Example 9: Using zip()
python
names = ["Alice", "Bob", "Charlie"]
ages = [25, 30, 35]
for name, age in zip(names, ages):
print(f"{name} is {age} years old")
# Output: Alice is 25, Bob is 30, Charlie is 35
Key Points to Remember
- Iterators are memory efficient: They don’t store all elements in memory at once
- One-time use: Once exhausted, they can’t be reused (unless reset)
- Lazy evaluation: Elements are computed on-the-fly
- Automatic in loops: Python automatically uses iterators in for-loops
Advantages of Iterators
- Memory efficient: Process large datasets without loading everything into memory
- Clean code: Simple and readable iteration syntax
- Flexible: Can create custom iteration behavior
- Universal: Works with any collection type
Common Built-in Iterables
- Lists:
[1, 2, 3] - Tuples:
(1, 2, 3) - Strings:
"hello" - Dictionaries:
{"a": 1, "b": 2} - Sets:
{1, 2, 3} - Files:
open('file.txt') - Range:
range(5)
Iterators are fundamental to Python and make working with collections efficient and elegant!
Iterator in Python – Interview Q&A
Basic Concept Questions
1. What is an iterator in Python?
Answer:
An iterator is an object that allows traversal through elements of a collection one at a time. It implements two methods:
__iter__(): Returns the iterator object itself__next__(): Returns the next element and raisesStopIterationwhen no more elements
Example:
python
my_list = [1, 2, 3] my_iter = iter(my_list) print(next(my_iter)) # 1 print(next(my_iter)) # 2
2. What is the difference between an iterable and an iterator?
Answer:
- Iterable: An object that can return an iterator (has
__iter__()method) - Iterator: An object that keeps state and produces next values (has both
__iter__()and__next__()methods)
All iterators are iterables, but not all iterables are iterators.
3. How does a for-loop work internally?
Answer:
A for-loop automatically:
- Calls
iter()on the iterable to get an iterator - Calls
next()repeatedly untilStopIterationis raised
Equivalent code:
python
# This for-loop:
for item in my_list:
print(item)
# Is equivalent to:
iterator = iter(my_list)
while True:
try:
item = next(iterator)
print(item)
except StopIteration:
break
Technical Questions
4. What happens when you call iter() on an iterator?
Answer:
Calling iter() on an iterator returns the iterator itself. This allows iterators to be used in for-loops.
Example:
python
my_list = [1, 2, 3] my_iter = iter(my_list) print(my_iter is iter(my_iter)) # True - same object
5. Why can’t you iterate over an iterator multiple times?
Answer:
Iterators are stateful and exhausted after use. Once StopIteration is raised, the iterator can’t be reset.
Example:
python
numbers = [1, 2, 3] num_iter = iter(numbers) list(num_iter) # [1, 2, 3] - exhausts iterator list(num_iter) # [] - empty because iterator is exhausted
6. How can you check if an object is an iterator?
Answer:
Check if it has both __iter__() and __next__() methods, or use collections.abc.Iterator.
Example:
python
from collections.abc import Iterator my_list = [1, 2, 3] my_iter = iter(my_list) print(isinstance(my_list, Iterator)) # False - list is iterable but not iterator print(isinstance(my_iter, Iterator)) # True - this is an iterator
Implementation Questions
7. How would you create a custom iterator?
Answer:
Create a class with __iter__() and __next__() methods.
Example:
python
class SquareNumbers:
def __init__(self, limit):
self.current = 1
self.limit = limit
def __iter__(self):
return self
def __next__(self):
if self.current > self.limit:
raise StopIteration
result = self.current ** 2
self.current += 1
return result
squares = SquareNumbers(3)
for num in squares:
print(num) # 1, 4, 9
8. What is the StopIteration exception?
Answer:StopIteration is raised by the __next__() method to signal that there are no more items to return. For-loops catch this exception to terminate.
Practical Questions
9. How would you create an infinite iterator?
Answer:
Create an iterator that never raises StopIteration.
Example:
python
class InfiniteCounter:
def __init__(self, start=0):
self.current = start
def __iter__(self):
return self
def __next__(self):
result = self.current
self.current += 1
return result
# Use with caution - will run forever without break condition
counter = InfiniteCounter()
for i in range(5): # Limit iteration
print(next(counter)) # 0, 1, 2, 3, 4
10. How can you iterate over a dictionary?
Answer:
Dictionaries provide several iterator methods:
Example:
python
student = {"name": "Alice", "age": 20, "grade": "A"}
# Iterate keys
for key in student:
print(key)
# Iterate values
for value in student.values():
print(value)
# Iterate key-value pairs
for key, value in student.items():
print(f"{key}: {value}")
Advanced Questions
11. What are the advantages of using iterators?
Answer:
- Memory efficiency: Process large datasets without loading everything into memory
- Lazy evaluation: Compute values on-demand
- Clean syntax: Simple iteration with for-loops
- Composability: Can chain iterators together
12. How do generators relate to iterators?
Answer:
Generators are a simpler way to create iterators. They automatically implement __iter__() and __next__() methods.
Example:
python
# Generator function
def square_numbers(limit):
for i in range(1, limit + 1):
yield i ** 2
# This creates an iterator
squares = square_numbers(3)
print(isinstance(squares, Iterator)) # True
13. What is the difference between iter() and __iter__()?
Answer:
iter(): Built-in function that calls__iter__()method__iter__(): Special method that should return an iterator
Example:
python
class MyList:
def __init__(self, data):
self.data = data
def __iter__(self):
return iter(self.data)
my_list = MyList([1, 2, 3])
# iter(my_list) calls my_list.__iter__()
14. How would you reset an iterator?
Answer:
Most iterators can’t be reset. Instead, create a new iterator:
Example:
python
numbers = [1, 2, 3] iter1 = iter(numbers) list(iter1) # [1, 2, 3] - exhausted # Create new iterator to "reset" iter2 = iter(numbers) list(iter2) # [1, 2, 3] - fresh iterator
15. How can you create an iterator from a function?
Answer:
Use generator functions with yield:
Example:
python
def countdown(n):
while n > 0:
yield n
n -= 1
# This creates an iterator
cd_iter = countdown(3)
print(list(cd_iter)) # [3, 2, 1]
Real-World Scenario Questions
16. How would you process a large file efficiently?
Answer:
Use file iterator to read line by line without loading entire file into memory:
Example:
python
def process_large_file(filename):
with open(filename, 'r') as file:
for line in file: # Uses iterator
process_line(line) # Process one line at a time
# Much more memory efficient than:
# with open(filename) as f:
# lines = f.readlines() # Loads everything into memory
17. How can you create a pagination iterator?
Answer:
Example:
python
class Paginator:
def __init__(self, data, page_size=2):
self.data = data
self.page_size = page_size
self.current_page = 0
def __iter__(self):
return self
def __next__(self):
start = self.current_page * self.page_size
end = start + self.page_size
if start >= len(self.data):
raise StopIteration
page = self.data[start:end]
self.current_page += 1
return page
data = [1, 2, 3, 4, 5, 6]
paginator = Paginator(data, page_size=2)
for page in paginator:
print(page) # [1, 2], [3, 4], [5, 6]
18. What’s wrong with this iterator code?
python
class BadIterator:
def __next__(self):
return 1
Answer:
It’s missing the __iter__() method. A proper iterator must implement both __iter__() and __next__().
Fixed:
python
class GoodIterator:
def __iter__(self):
return self
def __next__(self):
return 1