Table of Contents
What is a generator
A generator simply generates data that we are going to use someplace. For example ,if we want to generate some random characters , or if we want to generate a number in a mathematical series , or something that is infinite such as the series of even number , we can use a generator . A generator doesn’t use a lot of space , as data is computed dynamically.

To create a generator in python , we can create a generator function that uses the yield keyword in order to return the data . After that we create a generator object from this generator function to get the data .
We can also create a generator in python by directly creating a generator object using a generator expression .
A generator object can only be used once , it acts like an iterator , and when it has no more data it will raise a StopIteration exception .
Each generator object has a saved state , which is the state of its variables declared inside its generator function or generator expression
Creating the generator function
A generator function in python , is simply a function , that uses the yield keyword in order to return data .
def generateFlower():
''' generator function to generate a
generator flower object
'''
yield 'water'
yield 'seed'
yield 'every day'
yield 'quantity'
yield [3 , 1,2]
yield 30
yield 'flower'Creating the generator object
To create the generator object, we call the generator function that we have created .
We can access the data from the generator object , by either :
- using the next function , which will return the data from the generator object, or which will raise a StopIteration exception if there are no more data .
- or by using the created generator object , in a loop or in any place that takes an iterator , such as the constructor of a list ..
def generateFlower():
''' generator function to generate a
generator flower object
'''
yield 'water'
yield 'seed'
yield 'every day'
yield 'quantity'
yield [3 , 1,2]
yield 30
yield 'flower'
>>> flower = generateFlower()
>>> flower
<generator object generateFlower at 0x106b7d750>
# we have created the generator object
>>> next(flower)
'water'
# looping through our generator by calling next
>>> next(flower)
'seed'
>>> next(flower)
'every day'
>>> next(flower)
'quantity'
>>> next(flower)
[3, 1, 2]
>>> next(flower)
30
>>> next(flower)
'flower'
>>> next(flower)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
# no more items are available
# this will raise a StopIteration
# ##### next #######
>>> list(flower)
# ##### a generator object can only be used once #######
>>> list(generateFlower())
['water', 'seed', 'every day', 'quantity', [3, 1, 2], 30, 'flower']
# we created a new generator , since a generator
# can only be used once and we passed it to
# list
# ##### list #######
>>> flower = generateFlower()
>>> next(flower)
'water'
>>> next(flower)
'seed'
>>> list(flower)
['every day', 'quantity', [3, 1, 2], 30, 'flower']
# ##### next + list #######Generator Object state
The state of the variables defined inside the generator function is saved , for each generator object that is created from the generator function .
def generateCartesianProductOfTwoSets(setOne, setTwo):
'''
return the cartesian product of setOne by setTwo
e.g [1,2,3] * [4,5,6] = [(1,4) , (1,5) , (1,6) ,
(2,4) , (2,5) , (2,6) ,
(3,4) , (3,5) , (3,6)]
'''
lengthSetOne = len(setOne)
# get the length of set one
lengthSetTwo = len(setTwo)
# get the length of set two
counter = 0
# initialize the counter to zero
numberOfTuples = lengthSetOne * lengthSetTwo
# number of tuples of the cartesian product
# of setOne by setTwo
while counter < numberOfTuples:
# while counter less number of tuples
indexOfElementInSetOne = counter // lengthSetTwo
# element in set One is at the index
# counter // lengthSetTwo
# e.g A= a , b ; B = c , d , e =>
# generate the tuples starting a , next b
# a.c a.d a.e
# b.c b.d b.e
indexOfElementInSetTwo = counter % lengthSetTwo
# element in set Two is at the index
# counter % lengthSetTwo
yield (setOne[indexOfElementInSetOne], setTwo[indexOfElementInSetTwo])
# return the tuple e.g (a , b)
counter += 1
# increment the counter
>>> setOne = [1,2,3]
>>> setTwo = [4,5,6]
>>> lettersOne = 'lb'
>>> lettersTwo = 'aeo'
>>> setOneSetTwoProduct = generateCartesianProductOfTwoSets(setOne , setTwo)
>>> lettersOneLettersTwoProduct = generateCartesianProductOfTwoSets(lettersOne , lettersTwo)
>>> next(setOneSetTwoProduct)
(1, 4)
>>> next(lettersOneLettersTwoProduct)
('l', 'a')
>>> next(lettersOneLettersTwoProduct)
('l', 'e')
>>> next(setOneSetTwoProduct)
(1, 5)the lengthSetOne , lengthSetTwo , counter , numberOfTuples, setOne, setTwo state is saved for each generator object created from the generateCartesianProductOfTwoSets generator function .
What is a generator expression
A generator expression is used to create a generator object from a comprehension such as a list comprehension or dictionary comprehension … using parenthesis .
Instead of applying the comprension on all the elements at once , the comprehension is applied as needed .
opOnData = ( data * data for data in [1,2,3,4,5,6,7,]) # Create a generator object using a generator expression # A generator expression create a generator object from # a comprehension , such as list dictionary ... >>> next(opOnData) 1 >>> next(opOnData) 4 # instead of applying the comprehension on all the # data , we apply it when we want or when needed >>> [ data * data for data in [1,2,3,4,5,6,7,]] [1, 4, 9, 16, 25, 36, 49] # applying all comprehension on a list # calculate the square
>>> opData = ( data.upper() for data in ('a','b','c','d'))
>>> next(opData)
'A'
>>> next(opData)
'B'
>>> next(opData)
'C'
>>> next(opData)
'D'
>>> next(opData)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
