← Back to Python Course | Chapter 11: Advanced Python | Lesson 1 of 12

Python Iterators

Iterable vs. Iterator

An iterable is anything you can loop over with a for statement (a list, a string, a dict) -- an iterator is the separate object that actually keeps track of where you are in that sequence and hands back the next element each time it's asked.

Example: Iterable vs. Iterator

python
numbers = [1, 2, 3]
print(hasattr(numbers, "__iter__"))
it = iter(numbers)
print(hasattr(it, "__next__"))

The iter() and next() Functions

iter(some_list) converts an iterable into an iterator object, and calling next(that_iterator) repeatedly retrieves one element at a time, advancing the internal position with each call -- a for loop does exactly this under the hood automatically.

Example: The iter() and next() Functions

python
numbers = [1, 2, 3]
it = iter(numbers)
print(next(it))
print(next(it))

Creating Custom Iterators

Writing your own iterator class means implementing __iter__ (which conventionally returns self) and __next__ (which computes and returns the next value each time it's called) -- these two methods together are what make an object usable in a for loop.

Example: Creating Custom Iterators

python
class Counter:
    def __init__(self, limit):
        self.n = 0
        self.limit = limit
    def __iter__(self):
        return self
    def __next__(self):
        if self.n >= self.limit:
            raise StopIteration
        self.n += 1
        return self.n

for value in Counter(3):
    print(value)

The StopIteration Exception

Your __next__ method must raise StopIteration once there are no more items left to produce -- a for loop watches for this specific exception internally and uses it as the signal to stop looping cleanly, rather than treating it as an unhandled error.

Example: The StopIteration Exception

python
numbers = iter([1])
print(next(numbers))
try:
    next(numbers)
except StopIteration:
    print("No more items")

Practical Uses of Iterators

Because an iterator only computes the next value when explicitly asked, it never needs to hold an entire sequence in memory at once -- this lazy evaluation is what makes iterators efficient for processing very large or even effectively infinite sequences of data.

Example: Practical Uses of Iterators

python
def count_up_to(limit):
    n = 1
    while n <= limit:
        yield n
        n += 1

for value in count_up_to(3):
    print(value)

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.