Understanding Python Iterators: A Complete Guide

Last updated 5 months, 1 week ago | 422 views 75     5

Tags:- Python

Python is known for its elegant syntax and powerful features that make programming intuitive and efficient. One of these features is iterators, which provide a way to access elements of a collection (like lists or tuples) sequentially without exposing the underlying structure. This article delves into what iterators are, how they work, and how you can create your own.

What is an Iterator?

An iterator in Python is an object that implements the iterator protocol, which consists of two methods:

  • __iter__() — Returns the iterator object itself.

  • __next__() — Returns the next value from the iterator. Raises StopIteration when there are no more items.

Any object that has these two methods is considered an iterator.

Example:

numbers = [1, 2, 3]
iterator = iter(numbers)

print(next(iterator))  # Output: 1
print(next(iterator))  # Output: 2
print(next(iterator))  # Output: 3
print(next(iterator))  # Raises StopIteration

Iterables vs Iterators

These terms are often used interchangeably but are fundamentally different:

  • Iterable: Any object capable of returning its members one at a time, e.g., lists, strings, tuples. It implements __iter__() but not necessarily __next__().

  • Iterator: An object that keeps state and produces the next value when you call next().

lst = [10, 20, 30]
iter_obj = iter(lst)

print(hasattr(lst, '__iter__'))      # True (Iterable)
print(hasattr(lst, '__next__'))      # False
print(hasattr(iter_obj, '__next__')) # True (Iterator)

How for-Loops Use Iterators

Python's for loop internally uses the iter() and next() functions. Here’s how:

for element in [1, 2, 3]:
    print(element)

is internally equivalent to:

iterator = iter([1, 2, 3])
while True:
    try:
        item = next(iterator)
        print(item)
    except StopIteration:
        break

Creating Your Own Iterator

To create a custom iterator, define a class with __iter__() and __next__() methods.

Example: Countdown Iterator

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

for num in Countdown(5):
    print(num)

Output:

5
4
3
2
1

Generator vs Iterator

Generators are a simpler way to create iterators using the yield statement.

Example:

def countdown(n):
    while n > 0:
        yield n
        n -= 1

for number in countdown(5):
    print(number)

This generator function automatically creates an iterator and maintains state.

Advantages of Iterators

  • Memory Efficient: Processes items one at a time, especially useful for large datasets.

  • Lazy Evaluation: Items are computed as needed.

  • Composable: Can be easily chained and combined using tools like itertools.

Common Iterator Tools

Python’s itertools module offers powerful tools for iterators.

Examples:

  • count(start, step): Infinite counter

  • cycle(iterable): Infinite cycle through iterable

  • chain(iter1, iter2): Combines multiple iterables

import itertools

for i in itertools.islice(itertools.count(10, 2), 5):
    print(i)  # 10, 12, 14, 16, 18

Handling StopIteration Gracefully

When creating custom iterators, always raise StopIteration when done. However, from Python 3.3+, using return in a generator automatically raises StopIteration.

def numbers():
    yield 1
    yield 2
    return

 


Iterables vs Iterators vs Generators in Python

Feature Iterable Iterator Generator
Definition Any Python object capable of returning an iterator An object that produces elements one at a time A special kind of iterator created with yield
Examples list, tuple, dict, set, str, range Object from iter(list) Generator function or expression
Protocol Methods Must implement __iter__() Must implement __iter__() and __next__() Automatically implements both via yield
Exhaustible? No (can recreate iterators anytime) Yes (once consumed, can’t reset) Yes (once consumed, can’t reset)
Memory Usage Stores all items in memory Fetches items one by one Lazily generates values (memory-efficient)
Creation Built-in collections Call iter() on iterable Use yield or generator expression
Reset/Reusability Can get a new iterator again Cannot be reset (must recreate) Cannot be reset (must recreate)

 


Python Iterators – FAQ

❓ What is an iterator in Python?
An iterator is an object that implements the __iter__() and __next__() methods, allowing sequential access to elements one at a time.


❓ What is the difference between iterable and iterator?

  • Iterable: Any object you can loop over (e.g., list, tuple, dict, set). Provides an __iter__() method that returns an iterator.

  • Iterator: The actual object that produces elements one by one via __next__().


❓ Can iterators be reused?
No. Once an iterator is exhausted, it cannot be reset. You need to create a new iterator from the iterable.

nums = [1, 2, 3]
it = iter(nums)

print(next(it))  # 1
print(next(it))  # 2
print(next(it))  # 3
# next(it) -> StopIteration (exhausted)

❓ How is __next__() different from next()?

  • __next__() is the special method defined in the iterator object.

  • next(iterator) is the built-in function that internally calls iterator.__next__().


❓ Are generators and iterators the same?
Generators are a special type of iterator. They automatically implement __iter__() and __next__() using the yield keyword, making them easier to write.


❓ Why use iterators instead of lists?
Iterators are memory-efficient because they generate elements one at a time rather than storing all elements in memory at once.


Python Iterators Cheat Sheet

Concept Example Output
Get iterator from iterable it = iter([10, 20, 30])
Fetch next item next(it) 10
StopIteration exception After last element Error
Loop automatically consumes iterator for x in it: print(x) 20, 30
Custom iterator class Define __iter__() and __next__() Produces values
Convert iterator to list list(it) [10, 20, 30]
Check if object is iterable hasattr(obj, '__iter__') True/False
Check if object is iterator hasattr(obj, '__next__') True/False

Python Iterators Interview Questions

1. What is the difference between iterable, iterator, and generator in Python?

  • Iterable: an object that can return an iterator (list, tuple).

  • Iterator: object with __iter__() and __next__().

  • Generator: a special iterator built using yield.


2. What happens when an iterator is exhausted?
It raises a StopIteration exception. Iterators cannot be reset; you must recreate them.


3. How is for loop internally implemented using iterators?
A for loop does:

  1. Calls iter(iterable) → gets iterator.

  2. Calls next(iterator) repeatedly.

  3. Stops when StopIteration is raised.


4. What is the role of __iter__() in iterators?

  • For iterables, it returns a new iterator.

  • For iterators themselves, __iter__() usually returns self.


5. Can you manually iterate without a loop?
Yes, using next().

nums = [1, 2, 3]
it = iter(nums)
print(next(it))  # 1
print(next(it))  # 2

6. Is range() an iterator?
No. range() is an iterable. It returns an iterator when passed to iter().


7. Why are iterators memory efficient?
Because they do not store all items in memory—they generate each item on demand.


Conclusion

Iterators are a cornerstone of Python’s elegant design, enabling powerful and memory-efficient programming patterns. Understanding how to use and implement iterators allows you to work more effectively with collections and custom data streams.

Whether you’re working with built-in sequences or designing your own classes, iterators give you fine-grained control over data traversal.