In this tutorial, we are going to discuss about Generators in Python. We will also discuss about creating generators, their use and generator expressions.
Generators in Python
We have seen the iterators in python and how to create a custom iterator. But in order to do so, we have to implement a class with __iter__()
and __next__()
methods, manage internal values and raise a StopIteration exception when the sequence ends. This is time consuming and less helpful.
Generators are a simple and easy way to create iterators without having to worry about implementing __iter__()
and __next__()
methods and managing the iterator.
The generator function, returns an iterator object which can be used to iterate over a sequence of data.
Creating Generators
To create a generator in python is very simple. A generator is defined just like we define a normal function in python, but the return statement of a function is replaced with a yield statement.
A function definition is called as generator if it contains a yield statement. There might be multiple yield and return statements in a generator function. Both the yield and return statements return some value from the function.
The difference between a return statement and yield statement is that a return statement completely terminates the function whereas a yield statement just stops the function while saving its data and continues function execution from there when called successively.
Difference between Generator and Normal Function
Let's note down the difference between generator function and simple function.
-
A generator function always contains one or more yield statements.
-
A generator function returns an iterator object but does not start executing it immediately.
-
We do not need to implement the
__iter__()
and__next__()
methods explicitly, they are already implemented internally. We can iterate through an iterator usingnext()
method. -
The yield statement pauses the function and flow of control goes back to the caller function.
-
The state of a generator function is saved between successive function calls.
-
The generator function automatically raises StopIteration Error on further calls after function ends.
Let's have a look at a simple example of a generator function :
def gen_func():
print('First item : ')
yield 'abc'
value = 65
print('Second item : ')
yield value
value += 2
print('Third item : ')
yield value
iter_val = gen_func()
print("Object returned by generator function : ",iter_val)
next(iter_val)
Object returned by generator function : < generator object gen_func at 0x000001BDF4CD2750 >
First item :
'abc'
next(iter_val)
Second item :
65
next(iter_val)
Third item :
67
next(iter_val)
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
< ipython-input-19-14e2606495af > in < module >
----> 1 next(iter_val)
StopIteration:
Note that the local variable value is stored between calls to the generator function. The yield statement does not destroy local variables from a function unlike the return statement.
Once the last yield statement is executed, if we try to call the function again then it raises StopIteration Error.
We can also use for loops with generator objects just like we use with iterators. Let's see an example :
var = gen_func()
for it in var:
print(it)
First item :
abc
Second item :
65
Third item :
67
The for loop automatically ends when the generator object raises StopIteration Error.
Generators with a loop
The above example was an example of using a for loop with generator objects. But a generator function can contain a loop which makes a suitable terminating condition.
Let's have a look at one such example :
def get_square(value):
for x in range(value):
yield x * x
gen = get_square(5)
for i in gen:
print(i)
0
1
4
9
16
In the above example, we see how we can suitable condition for terminating the generator using a for loop.
Generator Expressions
We can also create simple one line generators using generator expressions. Similar to lambda or anonymous functions the generator expressions create anonymous generator functions.
The syntax for creating anonymous generator expressions is similar to syntax of list comprehensions which we saw while discussing lists. Only thing is the square brackets used are replaced by simple round parenthesis.
The list comprehension returns a complete list which is a sequence of data whereas a generator expression returns a 1
generator object which can be used to iterate through a sequence of data.
Let's have a look at example of generator expressions :
gen_exp = (2 ** x for x in range(5))
print("Generator Object : ", gen_exp)
for i in gen_exp:
print(i)
Generator Object : at 0x0000026D4F2F5408>
1
2
4
8
16
So, it is that simple to create a generator object and iterate through the sequence using Generator Expressions.
Let's conclude this tutorial here. In this tutorial we have discussed about Generators in python, their creation and use and generator expressions.
If you have any questions please comment below and also share your views and suggestions in the comment box.