Tuesday 28 June 2011

Python generators

  Generators is one of the important features of python whereby one can generate a series of values while maintaining the state of the function, consider generators as a function which when invoked will return a value and halts execution at that point till you invoke the next() function to continue its execution.
Generators looks like a conventional function, an important difference is that a generator includes the yield statement. It can be used by the for statement as if it were an iterator.

Here is an complete, but silly example of a generator.
>>> def values():
... yield 9
... yield 13
... yield 22
... yield 26
... yield 32
... return

In this case, we simply yield a fixed sequence of values. After yielding five values, it exits. Here’s how this generator is used by a for statement.
>>> for p in values():
... print p
...
9
13
22
26
32

A generator function returns a value not through return statement, but through an yield statement, in other words, the function yields a value at that point of time (when an yield statement is encountered) until its invoked again whereby it completes another cycle till an yield statement is encountered where it returns another value and so on, it has to be noted that such a function can also be terminated, lets look at a factorial example which I hope would be a simple reference.

def factorial():
    count=1
    fact=1
    while 1:
        yield fact
        count=count+1
        fact=fact*count

if __name__=="__main__":
    print "Factorial program using generators."
    func=factorial()
    print "Factorial of 1 =", func.next()
    print "Factorial of 2 =", func.next()
    print "Factorial of 3 =", func.next()
    print "Factorial of 4 =", func.next()
    print "Factorial of 5 =", func.next()

Output

Factorial program using generators.
Factorial of 1 = 1
Factorial of 2 = 2
Factorial of 3 = 6
Factorial of 4 = 24
Factorial of 5 = 120

Explanation:
As I mentioned earlier, a generator function works like a normal function until it hits an yield statement. where it returns a value (yield fact returns the value of fact at that moment) and halts there, maintaining the state of all the variables and the point where it yielded a value, then using the next() method, one can continue the execution of the function where it continues from where it left for another cycle till its an yield is encountered and so on, in this way we can generate a sequence of values like Fibonacci, factorial, square of numbers and so on.

Another example using for loop.
def factorial(n):
    count=1
    fact=1
    while count<=n:
        yield fact
        count=count+1
        fact=fact*count 
if __name__=="__main__":
    print "Factorial program using generators."
    for i in factorial(5):
        print i

Output
Factorial program using generators.
1
2
6
24
120

Explanation:
The above code is similar to previous example except that the for loop takes care of calling the next() function for five times and every time the generator function yields a value, the for loop body executes, when the generator function terminates, the for loop terminates as well.

9 comments: