Python built-in type (5) -- iterator type

Iterator refers to an object that can be called by the built-in function next and continuously returns the next value until the StopIteration error is finally thrown to indicate that it is impossible to continue returning the next value.

In fact, the above statement is just the definition of chivalrous iterator. In python, the iterator also needs to implement Iterable. The Iterable interface needs to return an iterator object, so that the iterator can be iterated by for statement.

Preliminary Cognition of Iterator Objects

In python, there is no built-in iterator type object, but str, tuple, list, dict, set and other types can be converted into an iterator object through the built-in function iter.

>>> s = 'abc'
>>> next(s)
Traceback (most recent call last):
File "<pyshell#27>", line 1, in <module>
    next(s)
TypeError: 'str' object is not an iterator
# The above error information shows that `str'is not an iterator
>>> it_s = iter(s)
>>> next(it_s)
'a'
>>> next(it_s)
'b'
>>> next(it_s)
'c'
>>> next(it_s)
Traceback (most recent call last):
File "<pyshell#31>", line 1, in <module>
    next(it_s)
StopIteration
# As can be seen from the above error-reporting information, `iter(str)'is an iterator

It's not very convenient to get the next value by calling the next(iterator) method constantly. python provides a more concise method, the for loop. Each time a for loop is executed, it is equivalent to calling a next(iterator) method until a StopIteration exception is caught and exits the loop.

>>> it_s = iter(s)
>>> for c in it_s:
    print(c)

a
b
c

# The example above is using for loop traversal iterator

The type Iterator in module collections is the abstract base class of iterators, and all iterators are instances of Iterator. That is, if an object is an instance of Iterator, it is an iterator.

from collections import Iterator

>>> isinstance(s,Iterator)
False

>>> isinstance(it_s,Iterator)
True

# The above information confirms that `str'is not an iterator and `iter(str)' is an iterator.

How to implement an iterator by oneself

According to the characteristics of python duck type, in our custom type, as long as we implement the _next()_ method, this method returns the next value every time it is called, and throws a StopIteration exception when it can not continue to return the next value (next(iterator) is actually calling the _next()_ method inside iterator.

Define your own iterator

>>> class MyIter():

    def __init__(self,max_value):
        self.current_value = 0
        self.max_value = max_value

    def __next__(self):
        if self.current_value < self.max_value:
            result = self.current_value
            self.current_value += 1
            return result
        else:
            raise StopIteration

Verify that the next method keeps returning the next value

>>> my_iter = MyIter(3)
>>> next(my_iter)
0
>>> next(my_iter)
1
>>> next(my_iter)
2
>>> next(my_iter)
Traceback (most recent call last):
  File "<pyshell#31>", line 1, in <module>
    next(my_iter)
StopIteration

Verify whether objects can be used for loops

>>> my_iter = MyIter(3)
>>> for i in my_iter:
    print(i)

Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>
    for i in my_iter:
TypeError: 'MyIter' object is not iterable

Is the verification object an Iterator instance?

>>> from collections import Iterator
>>> isinstance(my_iter,Iterator)
False

From the above verification, we can see that the object that only implements the _next() method is not an iterator, and the real iterator also needs to implement an iterative interface Iterable.

The relationship between Iterator and Iterable

Type Iterator in module collections is the abstract base class of iterators. In fact, it also defines type Iterable, which is the abstract base class of iteratable objects. First check their definitions by the help command:

>>> from collections import Iterator, Iterable
>>> help(Iterator)
Help on class Iterator in module collections.abc:

class Iterator(Iterable)
 |  Method resolution order:
 |      Iterator
 |      Iterable
 |      builtins.object
 |  
 |  Methods defined here:
 |  
 |  __iter__(self)
 |  
 |  __next__(self)
 |      Return the next item from the iterator. When exhausted, raise StopIteration
 |  
 |  ----------------------------------------------------------------------
 |  Class methods defined here:
 |  
 |  __subclasshook__(C) from abc.ABCMeta
 |      Abstract classes can override this to customize issubclass().
 |      
 |      This is invoked early on by abc.ABCMeta.__subclasscheck__().
 |      It should return True, False or NotImplemented.  If it returns
 |      NotImplemented, the normal algorithm is used.  Otherwise, it
 |      overrides the normal algorithm (and the outcome is cached).
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  __abstractmethods__ = frozenset({'__next__'})

>>> help(Iterable)
Help on class Iterable in module collections.abc:

class Iterable(builtins.object)
 |  Methods defined here:
 |  
 |  __iter__(self)
 |  
 |  ----------------------------------------------------------------------
 |  Class methods defined here:
 |  
 |  __subclasshook__(C) from abc.ABCMeta
 |      Abstract classes can override this to customize issubclass().
 |      
 |      This is invoked early on by abc.ABCMeta.__subclasscheck__().
 |      It should return True, False or NotImplemented.  If it returns
 |      NotImplemented, the normal algorithm is used.  Otherwise, it
 |      overrides the normal algorithm (and the outcome is cached).
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  __abstractmethods__ = frozenset({'__iter__'})

From the above code, it is clear that the iterator type Iterator inherits from the iteratable type Iterable and the iterative Iterable inherits from the object base class. The iterator Iterator type contains _iter() and _next() methods, while the iteratable type Iteratble only contains _iter_(). An iterator object is returned by _iter() and the _next() method of the iterator object is actually used to be looped.

Perfect yourself to implement an iterator

We now implement the MyIter type as an iterative interface Iterable, which implements the _iter_() method.

>>> class MyIter():

def __init__(self,max_value):
    self.current_value = 0
    self.max_value = max_value

def __iter__(self):
    return self

def __next__(self):
    if self.current_value < self.max_value:
        result = self.current_value
        self.current_value += 1
        return result
    else:
        raise StopIteration

Verify whether objects can be used for loops

>>> my_iter = MyIter(3)
>>> for i in my_iter:
print(i)

0
1
2

Is the verification object an Iterator instance?

>>> from collections import Iterator
>>> isinstance(my_iter,Iterator)
True

summary

  1. Every object that can act on a for statement loop is an Iterable iterative type.
  2. Any object that can act on the next() function is an Iterator iterator type.
  3. str, tuple, list, dict, set and other types are Iterable iterators, but not Iterator iterators. An Iterator iterator object can be obtained by Iterable iterator () method, so that they can be iterated by for statements.
  4. The essence of Python's for loop is to obtain an Iterator iterator object by calling the _iter()_ method of Iterable iteratable object, and then call the _next() method of Iterator iterator object continuously.

Keywords: Python

Added by srividya on Fri, 17 May 2019 17:40:07 +0300