Python Iterators: A Beginner’s Guide

🐍Python Iterators: A Beginner’s Guide

In Python, iterators are one of the most powerful yet misunderstood concepts. Beginners often use them without even realizing it—every time you loop over a list, tuple, or string, you are using an iterator behind the scenes. In this guide, we’ll dive deep into what iterators are, how they work, the difference between an iterable and an iterator, how to create custom iterators, and advanced concepts like StopIteration and generators.


📌 What is an Iterator in Python?

An iterator in Python is an object that allows us to traverse through a sequence of elements one at a time. Iterators implement two special methods:

  • __iter__() → Returns the iterator object itself.
  • __next__() → Returns the next value in the sequence. Raises StopIteration when no items are left.
Key Idea: An iterator “remembers” its state, so it knows which item to return next. Once exhausted, it cannot be reused unless recreated.

➡️ Example: Basic Iterator

nums = [10, 20, 30]
it = iter(nums)

print(next(it))  # 10
print(next(it))  # 20
print(next(it))  # 30
# next(it)  # Raises StopIteration

In this example, iter() creates an iterator from the list. The next() function fetches elements one by one until no elements remain.


📌 Iterator vs Iterable

These two terms often confuse beginners, but they are not the same:

  • Iterable: An object that can return an iterator (e.g., lists, tuples, strings). Implements __iter__().
  • Iterator: An object that produces data, one element at a time, using __next__().
Think of it like this: An iterable is like a book, while an iterator is like a bookmark that keeps track of where you left off when reading.

➡️ Example: Checking Iterable vs Iterator

from collections.abc import Iterable, Iterator

print(isinstance([1,2,3], Iterable))  # True
print(isinstance([1,2,3], Iterator))  # False

it = iter([1,2,3])
print(isinstance(it, Iterator))       # True

📌 Looping Through an Iterator

Most of the time, you don’t manually call next(). Instead, Python’s for loop automatically fetches items from an iterator until StopIteration is raised.

➡️ Example: Using for loop

nums = [10, 20, 30]
for x in iter(nums):
    print(x)

➡️ Example: Manual Iteration with try/except

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

📌 Creating a Custom Iterator

You can build your own iterator by defining a class that implements __iter__() and __next__(). This is useful when you want full control over iteration logic.

➡️ 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
        val = self.current
        self.current -= 1
        return val

for n in CountDown(5):
    print(n)

This custom iterator counts down from a given number until it reaches 0.


📌 The StopIteration Exception

When an iterator runs out of elements, it raises a StopIteration exception. Python’s for loop automatically handles this, but if you are using next() manually, you should be aware of it.

➡️ Example: Using next() with default

it = iter([])
print(next(it, "No more items"))  # Prints fallback message instead of error

📌 Generators: A Simpler Way to Build Iterators

Instead of writing full iterator classes, Python offers generators. A generator is a function that uses the yield keyword to produce values lazily.

➡️ Example: Countdown Generator

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

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

Generators are memory-efficient and widely used in real-world applications like reading files, streaming data, and pipelines.


📌 Real-World Uses of Iterators

  • Reading large files line by line without loading them fully into memory.
  • Processing infinite sequences (e.g., itertools.count()).
  • Building custom data pipelines with generators.
  • Working with APIs that stream data in chunks.

📌 FAQs on Python Iterators

Q1. Is every iterable also an iterator?

No. A list is iterable but not an iterator. You must call iter(list) to get an iterator.

Q2. Can an iterator be reused?

No. Once exhausted, an iterator cannot be reset. You must create a new iterator from the iterable.

Q3. Are generators and iterators the same?

Generators are a simpler way to create iterators. All generators are iterators, but not all iterators are generators.


📌 Exercises for Practice

  1. Create an iterator class EvenUpTo that yields even numbers up to a given number.
  2. Write a generator that yields the Fibonacci sequence up to n terms.
  3. Use iter() with a sentinel value to read input until “exit” is entered.
  4. Demonstrate how an iterator is exhausted by reusing it incorrectly.
  5. Use itertools.islice to get the first 10 numbers from itertools.count(100).

📌 Glossary

  • Iterable: Object capable of returning an iterator (like list, tuple, string).
  • Iterator: Object with __next__() method to fetch items one at a time.
  • StopIteration: Exception raised when iterator is exhausted.
  • Generator: Function that yields values lazily using yield.

✅ Conclusion

Iterators form the foundation of Python’s looping and data traversal mechanisms. Understanding the difference between iterables and iterators, handling StopIteration, and building your own iterators or generators is crucial for writing efficient Python code.

By practicing with the exercises provided, you will not only master Python Iterators but also gain confidence in working with data streams, loops, and memory-efficient coding techniques.


Related Posts

Continue Learning: Explore more beginner-friendly topics and practice materials in our Programming Resource Hub.

Post a Comment

0 Comments