In [17]:
#https://dbader.org/blog/python-generators
#https://stackoverflow.com/questions/9884132/what-exactly-are-pythons-iterator-iterable-and-iteration-protocols

iterable is an object that it can be used in iteration (with a for loop) by using iterator

iterator is an object that define how actually do the iteration: specifically what is the next element. That's why it must have __next__ method

To support iteration an object needs to implement the iterator protocol by providing the iter and next dunder methods.

Class-based iterators are only one way to write iterable objects in Python. Also consider generators and generator expressions.


In [2]:
numbers = [1, 2, 3]
for n in numbers:
    print(n)


1
2
3

In [13]:
iterator=iter(numbers)

In [14]:
next(iterator)


Out[14]:
1

In [10]:
next(iterator)


Out[10]:
2

In [11]:
next(iterator)


Out[11]:
3

In [12]:
next(iterator)


---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-12-3733e97f93d6> in <module>()
----> 1 next(iterator)

StopIteration: 

Iterator can be materializeted in list or tuple


In [21]:
iterator=iter(numbers)
list(iterator)


Out[21]:
[1, 2, 3]

In [25]:
iterator=iter(numbers)
a,b,c=iterator
print(a,b,c)


1 2 3

In [26]:
iterator=iter(numbers)
max(iterator)


Out[26]:
3

In [28]:
iterator=iter(numbers)
1 in iterator


Out[28]:
True

In [15]:
## Class based iterator
class BoundedRepeater:
    def __init__(self, value, max_repeats):
        self.value = value
        self.max_repeats = max_repeats
        self.count = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.count >= self.max_repeats:
            raise StopIteration
        self.count += 1
        return self.value

In [16]:
repeater = BoundedRepeater('Hello', 3)
for item in repeater:
    print(item)


Hello
Hello
Hello

In [19]:
repeater = BoundedRepeater('Hello', 3)
tuple(repeater)


Out[19]:
('Hello', 'Hello', 'Hello')