1Python provides a generator to create your iterator function.
2The generator is a different type of function that does not return a single value, instead it returns an iterator object with a sequence of values.
3In generators, the yield
keyword statement is used instead of the return
keyword statement.
def my_generator():
print("First value.")
yield 1
print("Second value.")
yield 2
print("Third value.")
yield 3
obj = my_generator()
print(next(obj))
print(next(obj))
print(next(obj))
'First value.'
1
'Second value.'
2
'Third value.'
3
In the above example, we created a function and included the yield
keyword statement. Because of the yield
keyword statement, this function is considered a generator function.
Here, we also created one reference variable and assigned that generator function to that variable, when we pass that variable to the next()
function as an input argument, then we get the yield
statement return value.
The stop iteration (StopIteraration
) error appears when you call the next()
function more than the yield
keyword statement; in other words, your generator function has no value for an iteration.
def my_generator():
print("First value.")
yield 1
print("Second value.")
yield 2
print("Third value.")
yield 3
obj = my_generator()
print(next(obj))
print(next(obj))
print(next(obj))
print(next(obj))
'First value.'
1
'Second value.'
2
'Third value.'
3
StopIteration
Here, we call the next()
function more than the yield
keyword statement present in our generator function, so we get a StopIteraration
error message.
It is possible to handle the StopIteration
error by using the try-except
block.
def my_generator():
print("First value.")
yield 1
print("Second value.")
yield 2
print("Third value.")
yield 3
obj = my_generator()
try:
print(next(obj))
print(next(obj))
print(next(obj))
print(next(obj))
except StopIteration:
print("StopIteration handled successfully.")
'First value.'
1
'Second value.'
2
'Third value.'
3
'StopIteration handled successfully.'
The try-except
block successfully handled the StopIteration
error in the example above.
It is also possible to call the next()
function multiple times using the looping statements.
def my_generator():
print("First value.")
yield 1
print("Second value.")
yield 2
print("Third value.")
yield 3
obj = my_generator()
for number in obj:
print(number)
'First value.'
1
'Second value.'
2
'Third value.'
3
Here, our generator function object is iterated using a for
statement.
The generator function calls like any other function; however, they pause when encountering the yield
keyword statement.
The first value from the iterator stream is sent to the calling environment; however, local variables and their states are saved internally.
def my_generator(number):
for i in range(number):
yield i
obj = my_generator(5)
for number in obj:
print(number)
0
1
2
3
4
Using the for
loop statement in the generator function, we created the yield
keyword statement, and our generator function also looped using a for
loop statement.
In the generator function, you cannot include the return
keyword. If you include it, then it will terminate the function.
The return keyword vs. yield keyword:
The return keyword statement returns a value and terminates the execution of a function.
A yield keyword statement returns a value and pauses execution while maintaining internal states.
def my_generator():
print("First value.")
yield 1
print("Second value.")
yield 2
return
print("Third value.")
yield 3
obj = my_generator()
print(next(obj))
print(next(obj))
print(next(obj))
'First value.'
1
'Second value.'
2
StopIteration
The generator function terminates execution after two yield
keyword statements due to the inclusion of the return
keyword in the generator function.
Similarly to the lambda function, we also create anonymous generator functions.
The generator expression is similar to the list comprehension expression, except that it uses round brackets (()
) instead of square brackets ([]
).
Generator expressions generate one item at a time, while list comprehensions generate the entire list.
A generator executes slowly, fetching items only when the next function is called. In this way, generator expressions are more memory efficient than equivalent list comprehensions.
colors_list = ["Red", "Blue", "Green"]
colors_filter_list = [i for i in colors_list]
colors_list_generator = (i for i in colors_list)
print(colors_filter_list)
print(colors_list_generator)
['Red', 'Blue', 'Green']
'<'generator object '<'genexpr'>' at 0x107adb350'>'
You can see that the list expression prints all elements in the output, while the generator expression returns an object.
In order to get the generator expression items, you need to call the next()
function.
colors_list = ["Red", "Blue", "Green"]
colors_list_generator = (i for i in colors_list)
print(next(colors_list_generator))
print(next(colors_list_generator))
print(next(colors_list_generator))
'Red'
'Blue'
'Green'
As a result, we get the items of the generator expression after passing the generator expression object to the next()
function.