In this post, we will look at the yield
keyword in Python and explore how it can be used to create efficient and elegant code.
What is the yield
Keyword in Python?
The yield
keyword is used in Python to define a generator function, which is a special type of function that returns an iterable object that can be used to produce a sequence of values. When a yield
statement is encountered in a generator function, it pauses the execution of the function and returns the value of the yield expression at that point. When the generator is called again, the function continues from the point where it left off, allowing you to produce a sequence of values without storing them in memory all at once.
Here is an example of a generator function that uses the yield keyword to produce a sequence of numbers:
def countdown(n):
while n > 0:
yield n
n -= 1
# Use the generator in a for loop
for i in countdown(10):
print(i)
In this example, the countdown generator
function uses the yield
keyword to return each value of n
as the loop iterates. This allows us to produce a sequence of numbers without storing them in memory all at once.
Using next()
with yield
in Python
In the above example we decided in advance how many times we wanted our function to yield
. What if we don’t know in advance? Check out the modified version below:
def countdown(n):
while n > 0:
yield n
n -= 1
# Create a generator object using the countdown function
generator = countdown(5)
# Call next() on the generator object to iterate over its values
print(next(generator)) # Output: 5
print(next(generator)) # Output: 4
print(next(generator)) # Output: 3
print(next(generator)) # Output: 2
print(next(generator)) # Output: 1
# When the generator is exhausted, calling next() raises a StopIteration exception
try:
print(next(generator))
except StopIteration:
print("Generator exhausted!")
Here we simple keep using next()
until the generator is “exhausted” meaning there is nothing left to yield. We used a try-except block to gracefully account for this possibility.
Benefits of Using the yield
Keyword in Python
There are several benefits to using the yield keyword in Python, including:
Efficiency: Because generator functions pause their execution and return a value when a yield statement is encountered, they use less memory than traditional functions that return a list or other iterable object. This can make your code faster and allow you to work with large datasets without running out of memory.
Flexibility: Generators can be used in a variety of contexts, such as in a for
loop or with the next() function. This allows you to write code that is flexible and easy to modify.
Readability: Generator functions are often more readable than traditional functions because they use the yield keyword to clearly indicate where values are being produced. This can make your code easier to understand and maintain. (Of course it takes a little practice for this benefit to become apparent…)
Examples of the yield
Keyword in Action
Now that you have a basic understanding of the yield keyword, let’s take a look at a few examples of how it can be used to create efficient and elegant code.
Generating an Infinite Sequence with the Yield Keyword in Python
One common use case for the yield keyword is to create a generator that produces an infinite sequence of values. Here is an example of a generator that produces an infinite sequence of random numbers:
import random
def random_numbers():
while True:
yield random.random()
# Use the generator in a for loop
for i in random_numbers():
print(i)
In this example, the random_numbers generator uses the random.random()
function to produce an infinite sequence of random numbers. Because the generator uses the yield keyword, it does not store all of the numbers in memory at once, making it an efficient and flexible way to generate random numbers.
Generating a Fibonacci Sequence using the yield
Keyword in Python
To use the yield
keyword in Python to create a Fibonacci sequence, you can define a generator function that uses the yield keyword to produce each value in the sequence. Here is an example:
def fibonacci(n):
a, b = 0, 1
for i in range(n):
yield a
a, b = b, a + b
# Use the generator in a for loop
for i in fibonacci(10):
print(i)
In this example, the fibonacci
generator function uses the yield
keyword to produce each value in the Fibonacci sequence. When the generator is called, it iterates over the sequence and uses the yield
keyword to pause the execution of the function and return each value. This allows you to produce the sequence of values without storing them all in memory at once.
(There are other ways to generate this sequence which are just as efficient, but this is a good example for the purposes of learning.)
Using the yield
keyword to generate Permutations.
Permutations are notorious for using up huge amounts of memory as their number grows so quickly relative to input size. This makes them a perfect candidate for the memory-saving yield
keyword in Python. Take a look at this code:
def permutations(elements):
if len(elements) <= 1:
yield elements
else:
for perm in permutations(elements[1:]):
for i in range(len(elements)):
yield perm[:i] + elements[0:1] + perm[i:]
for perm in permutations([1, 2, 3]):
print(perm)
Output:
[1, 2, 3]
[2, 1, 3]
[2, 3, 1]
[1, 3, 2]
[3, 1, 2]
[3, 2, 1]
Try the function with a bigger input list and it should give you results in a reasonable time up to a fairly large input size.
Conclusion
The yield
keyword in Python can be confusing to begin with. It is well worth getting used to it though, so that you can understand code where it appears and begin using it in your own projects to create efficient and elegant code compared to alternative approaches.
Happy computing!