How to Create a Python Iterator: A Guide
Iterators are absolutely everywhere in Python; it’s hard to learn even the basics without hearing the word “iterator” or “iterable”.
An iterator is an object that can be iterated upon. While there are some built-in objects upon which you can iterate, you can also define your own.
In this guide, we’re going to talk about Python iterators, how they work, and how you can use them in your code. We’ll constructor our own iterator so that you can learn about their core features in action. The code in this guide is compatible for Python 3.x installations.
Let’s get started!
What is an Iterator?
Iterators are objects upon which you can iterate. An iterator will return data from that object, one item at a time.
You can check whether an object is iterable by trying to run it through a for loop; if you can loop through the object, it means that it is iterable. Strings, lists, tuples, and dictionaries are examples of the built-in data types which are iterable objects.
An iterator object in Python must have two methods:
__iter__(): This allows you to retrieve an iterator.
__next__(): This allows you to get the next value in an iterator.
__ underscores are used in iterators because they denote special functions. To define an iterator, you must use these two special functions. Together, they are called the iterator protocol. These methods are usually pronounced as “iter and next methods”.
How to Build an Infinite Iterator
We’ll start with the basics: building an infinite iterator. This is the most simple type of iterator. It’s so simple that it will keep going on forever. We’ll fix this later in the tutorial.
Let’s start by defining a class called Cakes, which will be our iterator class:
class Cakes: def __init__(self, value): self.value = value
We’ve declared an
__init__ method which will be executed as soon as an object of our class is instantiated. The
__init__ method is called a constructor. In this example, our
__init__ method can take in one value: value.
Next, we’re going to create our iterator protocol:
def __iter__(self): return self def __next__(self): return self.value
__iter__ method is used to retrieve our iterator object. The
__next__ method allows us to retrieve the next value in the iterable object that we specify.
Let’s make sure our code works so far. We’ll do that by defining an object of our class like this:
cake = Cakes(["Vanilla Sponge"])
So far, so good! You may be thinking to yourself: why isn’t this code doing anything? That’s because our class only returns an iterator function.
We’ve got to iterate over our iterator to check if it works. We can do so using a for-in loop:
for c in cake: print(c)
Our code returns:
Vanilla Sponge Vanilla Sponge …
The curse of the Vanilla Sponge! It just keeps being printed to the console. What’s going on? We’ve just created our first iterator. It is very simple, but it works.
Testing Iterators Using for-in Loops in Python
Before we make our iterator useful, let’s take a moment to revise the concept of a for-in loop. In our last example, we wrote a for-in loop to test our code:
for c in cake: print(c)
The way that a for-in loop works is that it first creates an iterator of an object using an
__iter__() method. A for-in loop then calls
__next__() until no value is returned.
You can think of a
for-in loop as a simple
while loop. While there are values that an iterator can return, a for-in loop will return those values.
Creating a Useful Iterator
Our last iterator isn’t very useful. It only prints out the same value over and over again. With that said, it is still an iterator: it is capable of reading all the objects in an iterable.
We’re going to create an iterator that iterates over a Python array. This array contains a list of cakes.
To stop our iterator from repeating infinitely, we’re going to keep track of how many values are inside our iterable, and how many times our iterator has executed. This will allow us to stop our iterator from executing once it’s iterated through all the items in an iterable.
Open up a new Python file and paste in the following code:
class Cakes: def __init__(self, value): self.value = value self.max = len(value) self.count = 0 def __iter__(self): return self def __next__(self): if self.count < self.max: to_return = self.value[self.count] self.count += 1 return to_return else: raise StopIteration
This iterator is a bit more complicated than our last one. That’s why we built an infinite iterator first. In this iterator, we have initialized three values:
- value: The item over which we want to iterate.
- max: The number of items in our iterable.
- count: The number of times our iterator has executed.
__next__() method, we’ve added an ”if” statement. This statement checks whether the number of times our iterator has run (count) is less than the number of items over which our iterable should iterate (max).
If “count” is less than “max”, our iterator will find the next value in the iterable object. It will then add 1 to our “count” variable so we can keep track of how many objects are left to iterate over. Then, we return the value that we calculated.
It’s important to note that we assign a value to the variable “to_return” before we increment the “count” variable. This ensures that we can access the value on the current iteration of our iterator.
If we’ve iterated over every item in our list, an exception will be raised called StopIteration. This halts our program once we’ve iterated through every item in the list.
Let’s see if our iterator works. Add the following code to your main program and execute it:
cake = Cakes(["Vanilla Sponge"]) for c in cake: print(c)
Our code returns:
Let’s add in a few more items to our list and see what happens:
cake = Cakes(["Vanilla Sponge", "Carrot", "Coffee"]) for c in cake: print(c)
Our code returns:
Vanilla Sponge Carrot Coffee
We’ve done it! We’ve successfully created an iterator that loops through our list of cakes. You deserve a cake – or even just a cupcake – for getting this far.
Iterators allow you to create objects that can be iterated upon. An iterator can loop through a list, a string, or another iterable object, and perform a particular action.
Are you up for a challenge? Create an iterator that loops through a list of numbers and returns each number multiplied by two.
The code for this iterator will be similar to our above example – it will still use the iterator protocol – but it should multiply each number in a list by two before it is returned to the main program.
Now you’re ready to start writing your own iterators in Python like an expert!