Industrial manufacturing
Industrial Internet of Things | Industrial materials | Equipment Maintenance and Repair | Industrial programming |
home  MfgRobots >> Industrial manufacturing >  >> Industrial programming >> Python

Mastering Python Iterators: How They Work and How to Build Your Own

Python Iterators

Discover how Python iterators function, how to traverse them with for loops or the next() function, and how to create custom or infinite iterators using the iterator protocol.

Video: Python Iterators

Iterators in Python

Iterators are pervasive in Python. They underpin for loops, list comprehensions, generators, and many built‑in data structures, often working behind the scenes.

An iterator is simply an object that yields data one element at a time. In Python, any object that implements the __iter__() and __next__() methods is considered an iterator.

When an object can provide an iterator, it is called iterable. Most built‑in containers—lists, tuples, strings, dictionaries—are iterable. The built‑in iter() function calls an object's __iter__() method to obtain an iterator.


Iterating Through an Iterator

You can manually advance an iterator with the next() function. Once the iterator is exhausted, StopIteration is raised.

# define a list
my_list = [4, 7, 0, 3]

# get an iterator using iter()
my_iter = iter(my_list)

# iterate through it using next()

# Output: 4
print(next(my_iter))

# Output: 7
print(next(my_iter))

# next(obj) is same as obj.__next__()

# Output: 0
print(my_iter.__next__())

# Output: 3
print(my_iter.__next__())

# This will raise error, no items left
next(my_iter)

Output

4
7
0
3
Traceback (most recent call last):
  File "<string>", line 24, in <module>
    next(my_iter)
StopIteration

A more natural way to iterate is using a for loop, which automatically handles the iterator lifecycle.

>>>>> for element in my_list:
...     print(element)
...     
4
7
0
3

How the for Loop Works with Iterators

The for loop internally translates to:

for element in iterable:
    # do something with element

which is equivalent to the following logic:

# create an iterator object from that iterable
iter_obj = iter(iterable)

# infinite loop
while True:
    try:
        # get the next item
        element = next(iter_obj)
        # do something with element
    except StopIteration:
        # if StopIteration is raised, break from loop
        break

This shows that the for loop is essentially an infinite loop that relies on the iterator protocol and the StopIteration exception to terminate.


Building Custom Iterators

Creating an iterator from scratch is straightforward: implement __iter__() to return the iterator instance (often self) and __next__() to yield the next value or raise StopIteration when finished.

Below is an example that yields successive powers of two up to a user‑specified maximum exponent.

class PowTwo:
    """Iterator that yields powers of two."""

    def __init__(self, max=0):
        self.max = max

    def __iter__(self):
        self.n = 0
        return self

    def __next__(self):
        if self.n <= self.max:
            result = 2 ** self.n
            self.n += 1
            return result
        else:
            raise StopIteration

# create an object
numbers = PowTwo(3)

# create an iterable from the object
i = iter(numbers)

# Using next to get to the next iterator element
print(next(i))
print(next(i))
print(next(i))
print(next(i))
print(next(i))

Output

1
2
4
8
Traceback (most recent call last):
  File "/home/bsoyuj/Desktop/Untitled-1.py", line 32, in <module>
    print(next(i))
  File "<string>", line 18, in __next__
    raise StopIteration
StopIteration

Using a for loop with the custom iterator is equally simple:

>>>>> for i in PowTwo(5):
...     print(i)
...     
1
2
4
8
16
32

Python Infinite Iterators

Iterators can be unbounded. The built‑in iter() accepts a callable and a sentinel value: it repeatedly calls the function until the returned value equals the sentinel. For example:

>>>>> int()
0

>>> inf = iter(int,1)
>>> next(inf)
0
>>> next(inf)
0

Because int() always returns 0, iter(int, 1) never sees the sentinel, producing an infinite iterator.

You can also create your own infinite iterator, such as one that yields all odd numbers:

class InfIter:
    """Infinite iterator that returns successive odd numbers."""

    def __iter__(self):
        self.num = 1
        return self

    def __next__(self):
        num = self.num
        self.num += 2
        return num

Example run:

>>>>> a = iter(InfIter())
>>> next(a)
1
>>> next(a)
3
>>> next(a)
5
>>> next(a)
7

When working with infinite iterators, always provide a terminating condition to avoid endless loops.

Iterators are memory‑efficient because they produce items on demand. You can theoretically generate an unbounded sequence—like all odd numbers—without storing the entire set.

For a simpler way to create iterators, explore Python generators using yield.

Python

  1. Mastering Python Data Types: A Practical Guide
  2. Mastering Python Operators: A Comprehensive Guide
  3. Mastering Python's While Loop: Syntax, Examples, and Best Practices
  4. Mastering the Python Pass Statement: A Practical Guide
  5. Master Python Functions: Syntax, Types, and Practical Examples
  6. Mastering Python Function Arguments: Positional, Keyword, and Default Parameters
  7. Python Packages: Structure, Importing, and Best Practices
  8. Python List Operations: Creation, Access, Modification, and Advanced Techniques
  9. Mastering Python Tuples: Creation, Access, and Advanced Operations
  10. Mastering Python Dictionaries: Creation, Manipulation, and Advanced Techniques