Author: Chandu Bodduluri
A brief explanation about the Yield keyword in Python, the obscure cousin of the return statement.
Python has many utilities to make the lives of developers easy. One among such is the Yield keyword. It is used to replace the return statements that are generally used in Python functions. We’ll be taking a deep dive into the Yield keyword in Python and its usage in generator functions. But before we investigate the Yield keyword, we have to understand the concepts of generators and iterables.
Iterables – When a list is created, the items can be read one by one. Reading the items one by one is called iteration.
Here, iterablelist is an iterable and everything like ‘for and in’ that is used on lists, strings, and files is an iterable. Iterables can be read multiple times and the values are stored in memory. But this can be disadvantageous when there is a large number of values to be stored.
Generators – Generators are also iterables, but they can be iterated over only once i.e., they can be read only once. Also, generators compute values on the fly and they do not store values in the memory.
Here we can see that it is like the iterables list except that we have used () instead of .
But we cannot use another for i in generatorlist because generators can be read only once. It calculates 0, forgets about it, calculates 1, and then 4 and so on one by one.
Understanding Yield in Python
The Yield keyword is like the Return Statement which is used in Python to Return Values or objects. However, Yield returns a generator object when used within a function, unlike the Return Statement which simply returns a value. When we define a function and use Yield within the function, the function is known as a generator function because calling the function will return a generator object.
When we call a function within a program that contains Yield, as soon as the Yield function is encountered, the function execution is terminated, and an object of the generator is returned to the function caller. In simple terms, the Yield keyword converts the expression specified in the function into a generator object and returns it. If we want the values stored in the generator object, we need to iterate over the generator. We can understand this concept using the example below.
In the above example, we have created a generator function and we execute multiple Yield statements. Each time a Yield statement is called, values are returned which are stored in a generator object (the generator object concept will be further clarified in the consequent examples). We then iterate/loop over this generator object to output the values stored in it.
Differences between Yield and Return in Python
A normal function stores and returns the value directly. Generator functions, on the other hand, return generator objects that contain all the values to be returned and store them locally, saving a significant amount of memory. When a normal function is called, the execution is terminated as soon as it reaches the Return Statement. As a result, once a normal function has begun, it cannot be stopped. In the case of generator functions, however, it stops execution as soon as it reaches the first Yield statement and sends the value to the generator function. When we iterate over this value, the next Yield statement is executed, and the cycle goes on.
Example with Return Statement:
Example with Yield Statement:
In the above example, notice that when the function is called, only the generator object is returned. We must iterate over this object to output the individual elements.
Another difference between return and Yield is that we can use multiple Yield statements in a generator function whereas we can only use one Return Statement in a normal function. In contrast to the Return Statement, memory isn’t allocated when Yield statements are used whereas memory is allocated for all returned values in a Return Statement.
We can clearly understand the concept of Yield by using it in the Fibonacci program below instead of the traditional Return Statement.
Here, the Fibonacci program returns the top 25 Fibonacci numbers. When we use a Return Statement, we must create an array or a list, store the numbers in the list, and finally return the list. Instead, the Yield keyword automatically creates a generator object and we can iterate over the object to get the values on demand. This saves a lot of memory, especially when the range is large.
Advantages of Using the Yield Keyword
- The usage of the Yield keyword reduces memory consumption because based on the context, the generator function generates values on the fly and returns them one by one. The Return Statement instead, stores all the values in an array leading to higher memory consumption.
- When multiple continuous calls are made to a function containing a Yield statement, the execution always resumes from the last defined Yield statement thus saving time.
- Yield is a better option for large datasets when compared to the return. Also, when the size of the returned data is enormous, we can utilize Yield instead of putting it in a list to reduce memory consumption.
However, the disadvantage of Yield is that if the function call is not implemented properly, the Yield statements will lead to errors in the program. Trying to use Yield statements to improve time/space complexities will increase code complexity which makes it difficult to comprehend the code.
To summarize, you can use Python’s Yield statements to return multiple values from generator functions. It saves a lot of memory and boosts the code’s overall performance. It saves memory by storing the values to be returned as local variables states; additionally, each time the function is executed, it does not have to start from scratch because the preceding states are preserved.