Among a lot of interesting stuff in python the concept of Generators took me by surprise, so I will give an try to share the excitement with the rest of you out there who haven’t used it yet. Before I delve into this nice concept, I welcome you to the world of exotic flow control, truly Python has a charm of its own.
Imagine we have a set of numbers representing the fibonacci series in a list and then we traverse the list to get the numbers.
The data in the list is pre-generated using a formula, or manually entered by the user. This list can be really big, and then we have memory considerations. In cases where we really do not know how many of this elements we need to use, but still we have to pre-generate all of it just in case we need it. In such a scenario Pythons Generator comes to the rescue.
Here is a test function which is a generator, as it uses the yield keyword. We will run through the code step by step to understand how it works.
The output of the code would be as follows :
When we call the test function it doesn’t get executed instead, the Python interpreter gives a `generator object’. Calling a.next results the function beginning its execution – it prints ‘Hello Stranger’ and comes to a dead stop at the `yield’ statement, returning the value 1 to the caller. The function has gone back to its caller, but its `local state’ has been fully preserved. Another invocation of a.next results in the function restarting from where it had stopped earlier – it prints `Whats up’ and stops after returning the value 2 to the caller. Yet another invocation of a.next prints `Python rocks’ and returns 3 to the caller. If it is called again a exception will be raised, as the execution of the function has reached the end.
Going back to our first example of traversing a list for fibonacci numbers, we can achieved the same thing using a Generator function where the instead of the list we have a fibonacci function as the Generator. The Generator uses the yield keyword instead of a “return” , but “remembers” the exact point of execution where it returned. Next time the generator is called, it picks up where it left before, both in terms of function flow and in terms of variable values. Hence when needed and the function is called again the next number is calculated, thus no pre-storing of values are needed. A code snippet to show the yield in action :
So, now we can actually treat a function, as a list containing numbers, which does not need to be pre-generated rather can be calculated on the fly when the function is called. Each time the function is called, the next value is calculated. Very Interesting, isn’t it ?