In this lesson we are going learn about, Iterators
You often here these confusing words,
Iterable, Iterator, Iteration
Let’s break down and understand them.
It’s a repetition of a process, for example when you use for-loop,
you get an item from some thing, do some thing with that, right?
for x in something: do_something()
getting an item and doing something is a process,
which is repeated, until all the items are exhausted.
This is called iteration.
Any object, which allows us to iterate through.
In other words, a Python object which supports Iteration.
In Python, an iterable object, has an __iter__() method implemented,
By this method iterable object is capable of creating an iterator.
Python is full of iterables, You might have already seen lists, tuple,
files, str,dict etc….. they are all iterable.
Which means a list or tuple or a file is capable,
of creating an iterator object.
How to check an object is iterable?
If you check the names of any iterable with dir(), you will find
__iter__ dunder method. If the object has this method, that means
its an iterable.
empty_list =  dir(empty_list) output: #other names are not shown. [... '__iter__', ... ]
In simple words, iterable object which capable of creating iterator.
This created iterator works on iterable.
Iterables can be iterated any number of times.
To understand this let’s consider a list
And we will iterate through it twice with for-loop.
my_list = [1,2,3,4,5] print("First iteration") for i in my_list: print(i, end =" ") print("\nSecond iteration") for j in my_list: print(j, end= ' ') output: First iteration 1 2 3 4 5 Second iteration 1 2 3 4 5
Iterator is an object, which has ability to iterate,
through each element of an iterable.
Iterable creates iterator, that iterator is used to
iterate through iterable.
In simple words, iterator is Python object, which performs
iteration over iterable.
How iterator is created?
They are created by iter() function, internally its __iter__() method.
Iterator objects have __next__() implemented,
By using this __next__ method, iterator is able to iterate
Iterator knows their current state
Iterator objects,know there iteration count,
the count is maintained with internal state variable.
When the iteration reaches the last item StopIteration exception is raised.
Nothing resets the iteration count to zero. Because of this
an iterator can be iterated only once, to understand this
let’s look at the same list example.
We will create an iterator by the use of iter() method,
and try to iterate through it twice with a for-loop.
my_list = iter([1,2,3,4,5]) print("First iteration") for i in my_list: print(i, end =" ") print("\nSecond iteration") for j in my_list: print(j, end= ' ') output: First iteration 1 2 3 4 5 Second iteration
Notice we could only access the values during First iteration,
Nothing gets printed in the Second iteration.
Which proves that iterator can only be iterated once.
Iteration protocol is about how iterables actually work internally.
It’s just a fancy term.
Iteration protocol is combination of next() and iter() method
Next we will create our own iterator class, which uses
Creating user defined iterators
Iterators are implemented as classes, which have __iter__() and __next__()
Let’s build an iterator, which returns sequence of numbers.
class MyIterator(object): def __init__(self, n): self.x = 0 self.n = n def __iter__(self): return self def __next__(self): if self.x >= self.n: raise StopIteration("Can't go further") else: self.x += 1 return self.x mi = MyIterator(3) next(mi) next(mi) next(mi) output: 1 2 3 # the next(mi) will throw an exception next(mi) output: --------------------------------------------------------------------------- StopIteration Traceback (most recent call last) <ipython-input-27-a4ac8116c79b> in <module>() ----> 1 next(mi) <ipython-input-24-1298d5b4deeb> in __next__(self) 9 def __next__(self): 10 if self.x >= self.n: ---> 11 raise StopIteration("Can't go further") 12 13 else: StopIteration: Can't go further
Let’s create an iterator to get Fibonacci series.
class fib_itertor(object): def __init__(self,n): self.prev = 0 self.cur = 1 self.number = n self.count = 0 def __iter__(self): return self def __next__(self): if self.count < self.number: self.prev, self.cur = self.cur, self.prev + self.cur self.count += 1 return self.prev else: raise StopIteration("Reached desired number") fb1 = fib_itertor(10) for fb in fb1: print(fb, end=" ") output: 1 1 2 3 5 8 13 21 34 55
In the next lesson you will learn about, generators,
which is a special type of iterator.