Introduction to Generators in Python

Introduction to Generators in Python

4 mins read629 Views Comment
Updated on Nov 20, 2022 21:31 IST

Before diving into the concept of Generators in python, let’s take make ourselves familiar with the Iterators. Iterators are python objects that can be iterated upon, meaning that we can traverse through all the values in that iterator object. Iterators make use of the __iter__() and __next__() methods.

2022_08_MicrosoftTeams-image-27-1.jpg

Generators in Python are used to create iterators.  Basically implementing iterators manually can be lengthy and counterintuitive. This is where the generators in python can be very useful. Now that we have a brief understanding of generators in python, let’s take a look at key concepts associated with the Generators in python.

You can also explore: Introduction to Python – Features, Use Cases, Resources, and Applications 

Creating generators in Python: 

Creating python generators is fairly simple. Generators are implemented exactly like functions in python with a slight difference. Normally we use the return keyword with the functions to return a value but in the case of generators, we make use of the yield keyword. 

The only difference between the return keyword and the yield keyword is that the return statement ends the function entirely whereas the yield statement pauses the function, concurrently saving all its states, and further proceeds with making the subsequent function call. 

You can also explore: Variables in Python

Let’s take a look at an example implementation. 

Example: 

 
# A Python program to demonstrate
# implementation of generators in python
# A generator function
# A simple generator function
def my_generator():
n = 1
print('First call')
# Generator function with
# the yield statements
yield n
n += 1
print('Second call')
yield n
n += 1
print('Third call')
yield n
# the generator object
x= my_generator()
# iterate the generator object using
# the __next__() function and print result
print(x.__next__())
print(x.__next__())
print(x.__next__())
Copy code

Output:

First call
1
Second call
2
Third call
3

In the above example, the my_generator() function is called a Generator function and the variable x is called the Generator object. 

Note: As you can observe in the above output the value of n is stored between each generator call. This is because the local variables are kept intact whenever the yield statement is used. 

You can also explore: String Formatting in Python

Using Generators with Loops: 

We can also use the generators with loops in python. This helps us to avoid manually calling the generator using the __next__() method. Take a look at the below example for reference. Here we have used the my_generator() function that we implemented in the previous example but without the __next__() function call. 

Example:

 
# A Python program to demonstrate use of
# generator object with loops
# A generator function
# A simple generator function
def my_generator():
n = 1
print('First call')
# Generator function
# with the yield statements
yield n
n += 1
print('Second call')
yield n
n += 1
print('Third call')
yield n
# the generator object
x= my_generator()
# iterator through each yield
# of the generator object x.
for i in x:
# print the yield value
# from the generator
print (i)
Copy code

Output:

First call
1
Second call
2
Third call
3

Concept of Generator Expressions: 

Generator expressions in python are used to implement python generators easily. It works similar to the concept of anonymous functions in python, meaning that we can create anonymous generator functions too.  The syntax for creating a generator expression is as below. 

Syntax: 

my_generator_expression = (expression) 

Take a look at the below example for a simple implementation of generator expressions in python. 

Example: 

Here we will implement a simple generator expression to return the square of each number in a given range.

 
# A Python program to demonstrate
# implementation of
# generator expression in python
# given range
given_number = 5
#generator expression
squares = (x*x for x in range(given_number))
for i in squares:
print(i)
Copy code

Output:

0
1
4
9
16

As you can observe in the above output, our generator expression(ie, squares) returns the square of each number between 0 to 4, on each iteration of the loop. 

Use Cases of Generators: 

Now that we have made ourselves familiar with the concept of generators in Python, let’s take a look at some use cases. 

 1. As an Alternative for iterators: Generators are much easier to implement compared to iterators class counterparts.  For instance let’s suppose we need a function that should return a sequence of numbers starting from 0 on each iteration. Take a look at the below example code to implement the iterator for the same. 

Example:

 
# An iterable user defined type
class my_expression:
# Constructor
def __init__(self, max):
self.max = max
# method to initialize
# the iterator
def __iter__(self):
self.n = 0
return self
# method to return the next value
def __next__(self):
# Store current value of n
n = self.n
# base condition to Stop Iteration
if n > self.max:
raise StopIteration
# increment the num by 1
# for each iterator call
self.n = n + 1;
return n
# Prints numbers from 0 to 5
for i in my_expression(5):
print(i)
Copy code

Output:

0
1
2
3
4
5

Now take a look at the below generator that is equivalent to the above iterator class. 

 
def my_expression(max=0):
n = 0
while n < max:
yield n
n =n+ 1
# Prints numbers from 0 to 5
for i in my_expression(5):
print(i)
Copy code

Output:

0
1
2
3
4
5

2. To Increase Memory Efficiency: Generators only produce one item at a time for a sequences, whereas the in case of normal function, the entire sequence is generated and stored in the memory before releasing the return value. This make use of generators very useful wherever we are aiming for a minimum memory use. 

3.  Representing Infiniote stream: As we cannot store an infinite stream of data in memory, generators are an excellent choice as generators generate one item at a time and doesn’t need to be stored in the memory. For  instance take a look at the below function that in theory can return infinite numbers. 

Example: 

 
def mun_generator():
n = 0
while True:
yield n
n += 1
Copy code

Conclusion: 

In this article we have covered the following concepts associated with the generators:

  • What is a Generator in Python? 
  • How to create a generator in Python? 
  • Using generators with loops 
  • Concept of Generator Expression 
  • Some use cases of generators 
About the Author

This is a collection of insightful articles from domain experts in the fields of Cloud Computing, DevOps, AWS, Data Science, Machine Learning, AI, and Natural Language Processing. The range of topics caters to upski... Read Full Bio