Iteration Protocol and Generators in Python
This is 3rd article in series of Using advanced Python concepts the easy way. In this article I'll talk about Iteration Protocol and Generators of Python.
In recent articles, we talked about List comprehensions, slicing, Lamda and Filter. Iteration Protocol and generators are concepts that are little known to beginners. However, they are one of the core features of python.
First 2 articles are here.
1. Using advanced Python concepts the easy way ( List comprehensions and Slicing )
2. Advanced python concepts the easy way ( Lambda , Map and Filter )
Iteration Protocol
Iteration protocol is underlying stuff that allows you to iterate over any list, file etc.
Every object that is iteratable implements an interface called __next__ this method is supposed to allow iteration on every element of the object and raise StopIteration exception at the end of all the results.
Let's see it in action on a list.
myList = [1,2,3]
myIterator = iter(myList)
print (myIterator.__next__())
# prints 1
print (myIterator.__next__())
# prints 2
print (myIterator.__next__())
# prints 3
print (myIterator.__next__())
# Raises StopIteration
Now, Let's see how it works on for loop.
myList = [1,2,3]
for i in myList:
print(i)
1
2
3
Here for loop in internally calling __next__() method of list object myList and assining values to i this continues until StopIteration exception is raised.
A summary would be.
If an object implements a __next__ method which allows movement to next result, and raises StopIteration exeption at the end of results is called an iteratior. This kind of iterator can be iterated using for loop or some other iteration tool.
Generators
Generators are easy way to create iterators.
A generator function needs to have yield statement.
yield statment retains the state of function and it behaves like execution was paused.
return statement returns and terminates the exection of function, all the state would be lost.
Have a look at simple example.
def GeneratorFunc():
n = 1
while n < 10:
yield n**2
n += 1
if __name__ == '__main__':
it = GeneratorFunc()
print (next(it))
print (next(it))
print (next(it))
1
4
9
Above example is a generator function to generate square of numbers from 1 to 10. We are getting square of every number by using next() method.
Genrators are different that list comprehensions in a sense that, it returns one element at time, however, list comprehensions return an entire list.
Header image credits: Photo by Markéta Marcellová on Unsplash