Generator functions. Why and when should we use them.

You probably have heard of them. But as a beginner python programmer, we tend to ignore it's values because we fail to find uses of it. When we have loops and itertools and other fancy toys offered, why should we bother to understand them. If you want to take your programming  or understanding of Python to the next level, you must understand and use generators more and more.

Before we start, I want to make a simple program that prints square of (hence generates and delivers) 5 numbers from 1 to 5. So what is the first idea that pops up ? Let's use a for loop.


def square(N):
    for i in range(1, N+1):
        print i**2

>>>square(5)
1
4
9
16
25

Let's say, you need all the values generated for some other calculation. I know, above example is too lame . But imagine after some complicated calculations, you have generated some result.
So you probably will return all values together in an array. And to that, the first thought in our minds is, using a LIST. Let's use it. 

Now our function will look like this.

>>> def my_function(N):

    new_list = []

    for i in range(1, N+1):

        new_list.append(i**2)

    return new_list




>>> my_function(5)
[1, 4, 9, 16, 25]


All this looks easy. You probably are thinking...If generators are going to ruin this idea, I don't need it. Think again.

  1.  This LIST business will soon start becoming a nuisance as the  number of such calculations and variables increase (believe  me...thinking of new names for variables... SUCK).
  2.  What if you don't know your requirement. How many results  do you want.?
  3.  You had to create an array and it will take memory space  which becomes bigger with length of the list and size of each  element.
  4. Once you are dealing with very large list (imagine a million), generating a list of 1 million (let's assume integers) will take around 300 mb in memory.

A generator will make it all...Simpler. Here's the same example with generator function.


def square(N):
    for i in range(1, N+1):
        yield i**2

gen = square(5)

print gen.next()
print gen.next()
print gen.next()
print gen.next()
print gen.next()
print gen.next()

Result:

1
4
9
16
25

Traceback (most recent call last):

  File "D:\mydrive\Desktop\PyScripts\generators.py", line 14, in <module>
    print gen.next()
StopIteration
>>>

You can guess the reasons for the last trace-back. We went out of fuel. In order to avoid this, you can always use generator object to iterate.


def square(N):
    for i in range(1, N+1):

        yield i**2

gen_object = square(5)

for result in gen_object:

    print result

Result:

1
4
9
16
25


More fun with generators:

You can also make generator functions from list comprehensions. Use parenthesis instead of square bracket to make a gen function.


l = (x**2 for x in range(1,6))  

print l
for value in l:
    print value


Result:

<generator object <genexpr> at 0x0000000002D50F78>
1
4
9
16
25

Popular posts from this blog

Why should you visit Kashmir sooner?

CNTLM in Office

Rajasthan: The Best backpacking destination in India