Iterators and iterables.

1. Definitions

  1. An iterator is an object that contains a countable number of values that can be iterated, meaning that it is possible to traverse through all the values. In Python, an iterator is a object whose class implements the __next__() and __iter__() methods, in the following way:

In [ ]:
class yrange():
    
    def __init__(self, max_i):
        self.i = 0
        self.max_i = max_i
        
    def __iter__(self):
        return self # Compulsory when implementing the iterator protocol
    
    def __next__(self):
        if self.i > self.max_i:
            raise StopIteration # Compulsory (for finite iterators) when implementing the iterator protocol
        else:
            self.i += 1
            return self.i - 1

In [ ]:
iterator = yrange(5)
next(iterator)

In [ ]:
next(iterator)

In [ ]:
iterator.__next__() # This is also possible

In [ ]:
next(iterator)

In [ ]:
next(iterator)

In [ ]:
next(iterator)

Iterators are commonly used in for structures:


In [ ]:
for i in yrange(10):
    print(i, end=' ')
  1. An iterable is an object which one can iterate over. All iterators are iterable, but not all iterable objects are iterators. For example, a list is iterable and it not an iterator, unless it is converted in an iterator using the method iter():

In [ ]:
i = iter(['a', 'b', 'c']) # A list
i.__next__()

In [ ]:
i.__next__()

In [ ]:
i.__next__()

In [ ]:
i.__next__()

3. Iterators everywhere

Most of the native containers in Python can be populated with iterators:


In [ ]:
list(range(10))

In [ ]:
tuple(range(3,9))

Strings also support the iterator protocol:


In [ ]:
set('hola')

In [1]:
list_of_squares = [x*x for x in range(3)]

In [2]:
list_of_squares


Out[2]:
[0, 1, 4]