Python's Generator and Yield Explained

What are generators?

Generators are iterators, a kind of iterable you can only iterate over once.

What are iterators?

An iterator is an object that can be iterated (looped) upon. It is used to abstract a container of data to make it behave like an iterable object. Some common iterable objects in Python are - lists, strings, dictionary.

Every generator is an iterator, but not vice versa. A generator is built by calling a function that has one or more yield expressions.

The yield keyword behaves like return in the sense that values that are yielded get “returned” by the generator. Unlike return, the next time the generator gets asked for a value, the generator’s function, resumes where it left off after the last yield statement and continues to run until it hits another yield statement.

In simpler words, a generator is simply a function that returns a generator object on which you can call next() such that for every call it returns some value until it raises a StopIteration exception, signaling that all values have been generated.

Let’s take some examples of generators:

def generator_example():
    yield "Iterator first object"
    yield "Iterator second object"
    yield "Iterator third object"

As per the definition, the generator function creates a generator object you can verify this by just calling the function..

$ generator_example()

Output:

<generator object generator_example at 0x7f0980615348>

To get the actual result just, Store the object in a variable and call the next() method on it. Every call on next() will yield a single value until all the values have been yield.

gen_obj = generator_example()
next(gen_obj)

Output:

Iterator first object

Again from the definition, every call to next will return a value until it raises a StopIteration exception, signaling that all values have been generated so for this example we can call the next method 3 times since there are only 3 yield statements to run.

2nd Iteration

next(gen_obj)

Output:

Iterator second object

3rd Iteration

next(gen_obj)

Output:

Iterator third object

If you call next(gen_obj) for the fourth time, you will get StopIteration error from the Python interpreter.

4th Iteration

next(gen_obj)

Output:

Traceback (most recent call last):
...
StopIteration

Note: We can use generators with for loops directly, because a for loop takes an iterator and iterates over it using next() function. It automatically ends when StopIteration is raised.

for item in gen_obj:
    print(item)

Output:

Iterator first object
Iterator second object
Iterator third object

Let’s take an another example where we will generator random integer number between 0 to 500 and then will get using the generators.

import random

def random_number_generator():
    while True:
        number = random.randint(0, 500)
        yield number

Here the generator function will keep returning a random number since there is no exit condition from the loop.

num = random_number_generator()
next(num)

Output:

134

Generator Expression

Simple generators can be easily created on the fly using generator expressions. It makes building generators easy. The syntax for generator expression is similar to that of a list comprehension in Python. But the square brackets[] are replaced with round parentheses().

What is the difference between list comprehension and generator expression?

  • The major difference between a list comprehension and a generator expression is that a list comprehension produces the entire list while the generator expression produces one item at a time.
  • They have lazy execution ( producing items only when asked for ).

For this reason, a generator expression is much more memory efficient than an equivalent list comprehension.

Example:

# Initialize the list
my_list = [1, 7, 2, 11]

# square each term using list comprehension
list_squares = [x**2 for x in my_list]

# same thing can be done using a generator expression
# generator expressions are surrounded by parenthesis ()
gen = (x**2 for x in my_list)

print(list_squares)
print(gen)

Output

[1, 7, 2, 11]
<generator object <genexpr> at 0x8f4d3eb4cf70>

You can use next() to start getting output or you can also use for loop to iterator the output.

next(gen)

If you can to get generato ouput in list or tuple then you can directly convert generator object into the list or tuple.

list(gen)
tuple(gen)

Done!!

When are generators useful?

The key advantage to use the generators is that the “state” of the function is preserved, unlike with regular functions where each time the stack frame is discarded, you lose all that “state”. Also, generators do not store all the values in memory instead they generate the values on the fly thus making the ram more memory efficient.

Conclusion
Generator functions are ordinary functions defined using yield instead of return. When called, a generator function returns a generator object, which is a kind of iterator - it has a next() method. When you call next(), the next value yielded by the generator function is returned.

Explore More Python Posts

Using Twitter API with Python: Getting Tweets & Insights

Learn how to use the Twitter API with Python to get tweet information and insights. Extract valuable data for businesses and researchers with ease.

Read More
Accessing Facebook Data with Python: Examples for Post Likes, Views, and Profile Details

Learn how to access Facebook data using Python and the Facebook API. Get post likes, views, and comments, and retrieve profile details.

Read More
Python Design Patterns: Examples and Best Practices

Learn about Python design patterns with examples and discover best practices for writing maintainable and scalable code.

Read More
How to Use the YouTube API with Python: A Step-by-Step Guide

Learn how to access and retrieve information from YouTube using Python and the YouTube API. Get code examples and step-by-step instructions for impor…

Read More
Top 3 Python Frameworks for Web Development

Discover the most popular and efficient Python frameworks for building dynamic web applications. Get started today!

Read More
Debugging Made Easy with IPDB - The Python Debugger

Revolutionize the way you debug your Python code with IPdb, the advanced interactive debugger that streamlines your debugging process. Say goodbye to…

Read More