Python Iterators — The Iterator Protocol Explained

Python AdvancedIteratorsFree Lesson

Advertisement

Python Iterators — The Iterator Protocol Explained

Iteration is fundamental to Python. Every for loop uses iterators under the hood. Understanding the iterator protocol gives you power over custom iteration.

Learning Objectives

  • Understand the iterator protocol (__iter__ and __next__)
  • Create custom iterators with classes
  • Use the iter() and next() built-in functions
  • Implement infinite sequences safely

The Iterator Protocol

# Every iterable has __iter__ that returns an iterator
# Every iterator has __next__ that returns the next value

# Built-in iterables
nums = [1, 2, 3]
it = iter(nums)        # Calls nums.__iter__()

print(next(it))        # 1
print(next(it))        # 2
print(next(it))        # 3
# next(it)             # Raises StopIteration

Custom Iterator Class

class CountDown:
    def __init__(self, start):
        self.current = start

    def __iter__(self):
        return self

    def __next__(self):
        if self.current < 0:
            raise StopIteration
        value = self.current
        self.current -= 1
        return value

# Usage
for num in CountDown(5):
    print(num)  # 5, 4, 3, 2, 1, 0

Custom Iterable Class

class NumberRange:
    def __init__(self, start, end):
        self.start = start
        self.end = end

    def __iter__(self):
        return NumberRangeIterator(self.start, self.end)

class NumberRangeIterator:
    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
        value = self.current
        self.current += 1
        return value

# Can iterate multiple times
nums = NumberRange(0, 5)
print(list(nums))  # [0, 1, 2, 3, 4]
print(list(nums))  # [0, 1, 2, 3, 4] — works again!

Generator Functions (Simpler Iterators)

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

# This is equivalent to the class-based CountDown above
for num in countdown(5):
    print(num)

# Generators are iterators
gen = countdown(3)
print(next(gen))  # 3
print(next(gen))  # 2

Infinite Iterators

from itertools import count, cycle, repeat

# Infinite counter
for i in count(10):
    if i > 15:
        break
    print(i)  # 10, 11, 12, 13, 14, 15

# Cycle through items
colors = cycle(["red", "green", "blue"])
for _ in range(6):
    print(next(colors))  # red, green, blue, red, green, blue

# Repeat a value
ones = repeat(1, 5)
print(list(ones))  # [1, 1, 1, 1, 1]

Consuming Iterators

# list() consumes entire iterator
nums = [1, 2, 3]
print(list(iter(nums)))  # [1, 2, 3]

# enumerate, zip, map, filter all return iterators
scores = [95, 87, 91, 78, 85]
for i, score in enumerate(scores):
    print(f"Student {i}: {score}")

# itertools for advanced consumption
from itertools import islice, takewhile, dropwhile

# Take first 3
print(list(islice(count(), 3)))  # [0, 1, 2]

# Take while condition is true
print(list(takewhile(lambda x: x < 5, count())))  # [0, 1, 2, 3, 4]

Key Takeaways

  1. Iterators implement __iter__ and __next__
  2. Generators are the easiest way to create iterators
  3. Iterators are consumed once — they are not reusable
  4. StopIteration signals the end of iteration
  5. Use itertools for advanced iteration patterns

Advertisement

Need Expert Python Help?

Get personalized tutoring, project support, or professional consulting.

Advertisement