Iterators & Generators


Anything we can loop through, such as lists, strings or dictionaries are iterables.

a_list = [x for x in range(10)]
for i in a_list:


Generators are iterables too. However, we can only iterate through them once. Instead of storing all the values in memory, they generate it on the fly.

Generators allow us to declare functions that behave like an iterator.

g = (x for x in range(10))
for i in g:

The syntax is almost the same as above, except that we have used round brackets instead of square ones.

Side Notes:

That does not mean we cannot create a tuple with list comprehension. We can still do it like this:

t = tuple(x for x in range(10))


The yield keyword is used within a function so as to return a generator.

def generate():
a_list = range(10)
for i in a_list:
yield i*i
generator = generate()
for i in generator:
# if you run the for-loop again on generator, it will not produce any output

This will be handy when we know the function will return a large set of values which we only need to read once.

When we call the function, the function does not run. It returns the generator object. The function is run only when the generator object is accessed in the for loop later.

StopIteration will be raised when the generator stops yielding (done automatically). When the function runs, and it does not hit the yield keyword, the generator is empty.