oursolutionarchitectoursolutionarchitect
  • Python Questions and Answers
  • Python - Programming Examples
  • Python - Quick Guide
  • Python - Useful Resources
  • Python - Discussion
    • Selected Reading
    • Q&A

    Python - Iterators


    Iterator in Python is an object representing a stream of data. It follows iterator protocol which requires it to support __iter__() and __next__() methods. Python's built-in method iter() implements __iter__() method. It receives an iterable and returns iterator object. The built-in next() function internally calls to the iterator's __next__() method returns successive items in the stream. When no more data are available a StopIteration exception is raised.

    Python uses iterators are implicitly while working with collection data types such as list, tuple or string. That's why these data types are called iterables. We normally use for loop to iterate through an iterable as follows −

    for element in sequence:
     print (element)
    

    Python's built-in method iter() implements __iter__() method. It receives an iterable and returns iterator object.

    Example

    Following code obtains iterator object from sequence types list, string and tuple. The iter() function also returns keyiterator from dictionary. However, int id not iterable, hence it produces TypeError.

    print (iter("aa"))
    print (iter([1,2,3]))
    print (iter((1,2,3)))
    print (iter({}))
    print (iter(100))
    

    It will produce the following output

    <str_ascii_iterator object at 0x000001BB03FFAB60>
    <list_iterator object at 0x000001BB03FFAB60>
    <tuple_iterator object at 0x000001BB03FFAB60>
    <dict_keyiterator object at 0x000001BB04181670>
    Traceback (most recent call last):
       File "C:\Users\user\example.py", line 5, in <module>
          print (iter(100))
                ^^^^^^^^^
    TypeError: 'int' object is not iterable
    

    Iterator object has __next__() method. Every time it is called, it returns next element in iterator stream. When the stream gets exhausted, StopIteration error is raised. Call to next() function is equivalent to calling __next__() method of iterator object.

    Example

    it = iter([1,2,3])
    print (next(it))
    print (it.__next__())
    print (it.__next__())
    print (next(it))
    

    It will produce the following output

    1
    2
    3
    Traceback (most recent call last):
       File "C:\Users\user\example.py", line 5, in <module>
          print (next(it))
                ^^^^^^^^
    StopIteration
    

    Example

    You can use exception handling mechanism to catch StopIteration.

    it = iter([1,2,3, 4, 5])
    print (next(it))
    while True:
       try:
          no = next(it)
          print (no)
       except StopIteration:
          break
    

    It will produce the following output

    1
    2
    3
    4
    5
    

    To define a custom iterator class in Python, the class must define __iter__() and __next__() methods.

    In the following example, the Oddnumbers is a class implementing __iter__() and __next__() methods. On every call to __next__(), the number increments by 2, thereby streaming odd numbers in the range 1 to 10.

    Example

    class Oddnumbers:
    
       def __init__(self, end_range):
          self.start = -1
          self.end = end_range
    
       def __iter__(self):
          return self
    
       def __next__(self):
          if self.start < self.end-1:
             self.start += 2
             return self.start
          else:
             raise StopIteration
    
    countiter = Oddnumbers(10)
    while True:
       try:
          no = next(countiter)
          print (no)
       except StopIteration:
          break
    

    It will produce the following output

    1
    3
    5
    7
    9
    

    Asynchronous Iterator

    Two built-in functions aiter() and anext() have been added in Python 3.10 version onwards. The aiter() function returns an asynchronous iterator object. It is an asynchronous counter part of the classical iterator. Any asynchronous iterator must support __aiter__() and __anext__() methods. These methods are internally called by the two built-in functions.

    Like the classical iterator, the asynchronous iterator gives a stream of objects. When the stream is exhausted, the StopAsyncIteration exception is raised.

    In the example give below, an asynchronous iterator class Oddnumbers is declared. It implements __aiter__() and __anext__() method. On each iteration, a next odd number is returned, and the program waits for one second, so that it can perform any other process asynchronously.

    Unlike regular functions, asynchronous functionsare called coroutines and are executed with asyncio.run() method. The main() coroutine contains a while loop that successively obtains odd numbers and raises StopAsyncIteration if the number exceeds 9.

    Example

    import asyncio
    
    class Oddnumbers():
       def __init__(self):
          self.start = -1
    
       def __aiter__(self):
          return self
          
       async def __anext__(self):
          if self.start >= 9:
             raise StopAsyncIteration
          self.start += 2
          await asyncio.sleep(1)
          return self.start
          
    async def main():
       it = Oddnumbers()
       while True:
          try:
             awaitable = anext(it)
             result = await awaitable
             print(result)
          except StopAsyncIteration:
             break
             
    asyncio.run(main())
    

    It will produce the following output

    1
    3
    5
    7
    9