Python Iterator(__iter__ and __next__)

In this Python article, we will discuss iterator in python, python iterator class, its use, different ways of implementation, and multiple examples in detail. So let’s Begin.

1. What is an Iterator in Python?

Iterators can be defined as an object that can be iterated upon, which means that the user can traverse over its values one by one.

Iterator can be used to iterate over different objects which include lists, tuples, dictionaries, and sets.

Technically in Python, iterator object uses the iterator protocol, which consists of the two methods, __iter__() and __next__(). The iterator object is created using the iter() and the next() method is used for iteration. We will discuss the working of each of them further in this article.

If we observe, we can find the iterators at many places in Python. Majorly in use with for loops and generators but it generally remain hidden in plain sight.

1.1. Difference between Iterator and Iterable?

An iterable is an object that implements __iter__ method and it is expected to return an iterator object.

In specific terms, we can say that lists, sets, tuples, and dictionaries, all are iterable objects. These iterable are “containers” that are used to get an iterator from.

Hence, all the types mentioned above consist of an __iter__()  method which is used to get an iterator.

Python Iterator
Python Iterator

Let’s implement an example to iterate over a list using iter() and next() methods.

small_list = ["I", "am", "coding", "and", "learning"]
iterable_variable = iter(small_list)

print(next(iterable_variable))
print(next(iterable_variable))
print(next(iterable_variable))
print(next(iterable_variable))
print(next(iterable_variable))
Output
I
am
coding
and
learning

Now you might be wondering what is the difference between iter(x) and x.__iter__() and between next(x) and x.__next__(). And the answer is that there is no difference at all. They both act in the same way and return the same objects.

Read more: User defined functions in Python

Let’s take one more example, we will iterate using the __next__() and __iter__() method.

number_list = [3, 9, 81, 1729]
iterable_variable = number_list.__iter__()

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

print(iterable_variable.__next__())
print(iterable_variable.__next__())
print(iterable_variable.__next__())
print(iterable_variable.__next__())
Output
3
9
81
1729

1.3. How does ‘for’ Loop work with Iterator in Python?

As we have discussed the for loop, we have seen that the for loop can automatically iterate through a list or any other iterable.

Let’s check how does for loop implementation looks like in Python.

# EXAMPLE
# for any_variable in any_iterable:
# pass

# Actual implementation of for loop
iterable_object = iter(any_iterable)

while True:                # infinite loop
  try:
    # getting any next item
    each_value = next(iterable_object)
    # statements

  except StopIteration:
    # if StopIteration raised, break the loop
    break

In the above example, we can see that internally the for loop makes an iterator object, iterable_object by using iter() on the iterable and continues to call the next(iterable_object) until all the elements are processed.

Ironically, the for loop used here is actually an infinite while loop with a stop condition to avoid any error when an exception is raised.


3. How to create a custom Iterator?

Python allows users to create their own iterator from basics. To do so, we use the __iter__() and the __next__() methods.

Iterator object is returned using the __iter__() method. Creation can be performed, if it is needed. Whereas, the __next__() method has to return the next element in the provided sequence.

Once the end is reached with call-in proper order, it must raise StopIteration.

Let’s take an example to understand better.

class Run:

  def __init__(self, highest):
    self.highest = highest

  # Creating an iterator object
  def __iter__(self):
    self.value = 0
    return self

  # To move to next element using __next__
  def __next__(self):

    # Storing the current i value
    value = self.value

    # Stop iteration if limit is reached
    if value > self.highest:
      raise StopIteration

    # increment & return old value
    self.value = value + 15
    return value


# Outputs the numbers
for x in Run(140):
  print(x)

print("\n")
# One output
for i in Run(5):
  print(i)
Output
0
15
30
45
60
75
90
105
120
135

0

Read more: Learn more about Python class and its different methods


4. How to use Infinite Iterator in Python?

There can be certain conditions when we want our iterator to continue unless a certain condition is met. For such scenarios, we use infinite iterators. These iterators has to be stopped intentionally.

But if we fall into the trap of infinite iterators, then it will never end. Hence, extra care needs to be there while handling such iterators.

For example, if we call the built-in function iter() with two arguments, the first argument has to be an object which is callable (function) and the second argument will be the sentinel(“A value that signifies the sequence end”). The iterator will continue to call this function until the sentinel value matches the returned value.

int()

infinite_trap = iter(int,1)
print(next(infinite_trap))
print(next(infinite_trap))
print(next(infinite_trap))
print(next(infinite_trap))
print(next(infinite_trap))
print(next(infinite_trap))
Output
0
0
0
0
0
0

Here, in the above code, the int() function will always return the value 0. Therefore, calling iter(int,1) will return an iterator that calls int() until the value reaches 1. But the value will never reach 1 and we fall in an infinite iterator.

Iterators have the advantage of saving resources, for example, without storing the whole number system in memory we can use an iterator to generate the numbers as per our requirements.

Let’s take an example and let’s try to create our own infinite iterator.

class user_iterator:

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

  def __next__(self):
    value = self.value
    self.value += 3
    return value


call = iter(user_iterator())
print(next(call))
print(next(call))
print(next(call))
print(next(call))
print(next(call))
Output
0
3
6
9
12

And so on. It will continue generating the next number till the time we call the next method. Without memory storing the whole number system, we could get the numbers in table 3. We may have endless items in finite memory (theoretically).


5. Conclusion

Finally, if we sum up, in this article we have covered:

  • What is an Iterator and why is iterator used.
  • Difference between Iterator and Iterable.
  • How does ‘for’ loop work with an iterator?
  • How to create or design a custom Iterator and how to build our own iterator with various examples?
  • How to use infinite Iterator and how to create own iterators in Python?

Helpful Links

Please follow the Python tutorial series or the menu in the sidebar for the complete tutorial series.

Also for examples in Python and practice please refer to Python Examples.

Complete code samples are present on Github project.

Recommended Books


An investment in knowledge always pays the best interest. I hope you like the tutorial. Do come back for more because learning paves way for a better understanding

Do not forget to share and Subscribe.

Happy coding!! ?

Recommended -

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x
Index