Thanks to Shaumik Daityari for kindly helping to peer review this article.
When we call a function in Python, the function will normally start working until it encounters a return
, exception
, or reaches its end – after which it returns control back to the caller. Whenever you call that function again, the process will start from scratch!
Say that you asked a person to track the red cars on the road. The person will keep getting a question asking them if they spotted a red car or not, and the person in turn would answer with either ‘yes’ or ‘no’. If the person answered ‘yes’, the number of times the red car was spotted will increase.
Let’s see how we can do this in Python:
import time
def red_cars(answer):
n = 0
while True:
if answer == 'yes':
n = n + 1
return n
else:
return n
stop = time.time() + 5 * 60
while time.time() < stop:
answer = raw_input('Did you spot a red car on the road? ("yes" or "no"): ')
times = red_cars(answer)
print 'You have spotted ' + str(times) + ' cars so far!'
If you run the program, what do you notice? Did you notice that the number of times for the ‘yes’ answer is always capped at 1
, and when you answer ‘no’ the number of times gets 0
regardless of answering ‘yes’ before?
Here is where Python’s yield
keyword comes into play. yield
is a means by which we temporarily hand control to the caller, and expect to continue from the point at which control has been handed over.
Before giving the solution to the above example, let me demonstrate a very simple example to better illustrate how yield
works.
Say we have the following simple Python script:
def step_by_step():
return 'step 1'
return 'step 2'
return 'step 3'
step = step_by_step()
for i in range (3):
print step
If you run the script, you will get the following output:
step 1
step 1
step 1
Now, if we use yield
instead, as follows:
def step_by_step():
yield 'step 1'
yield 'step 2'
yield 'step 3'
step = step_by_step()
for i in range (3):
print step.next()
The output would be as follows:
step 1
step 2
step 3
As you can see, we were able to create a series of values, as for each call the function continues from the point where it yields a value. This type of function is called a generator. Such function creates a generator iterator, as with each call to the method next()
we move to the next yield
statement.
If we come back to our main example (red cars), it can be written as follows to perform the required task:
import time
def red_cars(answer = None):
n = 0
while True:
if answer=="yes":
n = n + 1
answer = yield n
else:
answer = yield n
car_color = red_cars()
car_color.next()
stop = time.time() + 5 * 60
while time.time() < stop:
answer = raw_input('Did you spot a red car on the road? ("yes" or "no"): ')
print 'You have spotted ' + str(car_color.send(answer)) + ' cars so far!'
Thus, as we can see, yield
is deemed important when we are interested in resuming execution at the last point where the function (generator) exited, and where we are also interested in keeping the values of local variables between the different calls – unlike normal functions, where such values are destroyed when exiting the function.
There are, however, other uses of yield
. For instance, you can use yield
if you have a function which returns a sequence (for example, rows in an excel sheet) and you need to iterate over the sequence without having each value in memory at once. That is, to save memory.
yield
can also be used when working with iterables, where we have a large list that is difficult to pass between functions. For instance, Python’s inbuilt functions for permutations and combinations in the itertools module use yield
.
Frequently Asked Questions (FAQs) about the Yield Keyword in Python
What is the difference between the yield and return keywords in Python?
The yield and return keywords in Python are used in functions, but they serve different purposes. The return keyword is used when you want a function to produce a value and then terminate. Once a function returns a value, it is done executing and control is passed back to the caller. On the other hand, the yield keyword is used in a function like a return statement, but it produces a value and suspends the function’s execution. The function can be resumed later on from where it left off, allowing it to produce a series of values over time, instead of computing them all at once and sending them back like a list.
How does the yield keyword work in Python?
The yield keyword in Python is used in a function with a loop to create an iterator. When the function is called, it returns an iterator, but does not start execution immediately. When the iterator’s next() method is called, the function starts executing. Once it encounters the yield keyword, it returns the argument passed to yield and pauses execution. The function can be resumed from where it left off by calling next() again, allowing the function to produce a series of values over time, behaving as a generator.
Can you provide an example of using the yield keyword in Python?
Sure, here’s a simple example of using the yield keyword in Python:def simple_generator():
yield 1
yield 2
yield 3
for value in simple_generator():
print(value)
In this example, simple_generator is a generator function because it uses the yield keyword. When we iterate over the generator object returned by simple_generator(), it yields 1, then 2, then 3, pausing its execution between each yield.
What are the benefits of using the yield keyword in Python?
The yield keyword in Python allows you to write functions that can produce a sequence of results over time, rather than computing them all at once and returning them in a list for example. This can be particularly useful when the result set is large and you want to save memory. It also allows you to create your own iterable objects and use them with Python’s for loops, comprehensions, and other functions that expect an iterable.
Can a function contain both yield and return statements in Python?
Yes, a function in Python can contain both yield and return statements. However, it’s important to note that once a return statement is executed, the function’s execution is terminated, and control is passed back to the caller. So if a return statement is executed before a yield statement, the yield statement will never be reached. Conversely, if a yield statement is executed first, the function will be paused and control will be passed back to the caller, but the function can be resumed later on, at which point the return statement can be executed.
Can I use the yield keyword in a recursive function in Python?
Yes, you can use the yield keyword in a recursive function in Python. However, you need to remember to iterate over the recursive call and yield each value, otherwise you’ll get a generator object instead of the values you expect.
What is the difference between a generator function and a normal function in Python?
The main difference between a generator function and a normal function in Python is that a generator function uses the yield keyword and a normal function uses the return keyword. When a generator function is called, it returns a generator object without even beginning execution of the function. When the next() method is called for the first time, the function starts executing until it reaches the yield keyword, which produces a value. The function then pauses execution and control is passed back to the caller. On the other hand, when a normal function is called, it starts execution immediately and runs to completion, returning a value.
Can I use multiple yield statements in a single function in Python?
Yes, you can use multiple yield statements in a single function in Python. When the function is called, it will yield a value each time it encounters a yield statement, pausing its execution and passing control back to the caller. The next time the function’s next() method is called, it will resume execution from where it left off and run until it encounters the next yield statement.
How can I catch the StopIteration exception raised by a generator function in Python?
When a generator function in Python has no more values to yield, it raises a StopIteration exception. You can catch this exception by using a try/except block. Here’s an example:def simple_generator():
yield 1
yield 2
yield 3
gen = simple_generator()
while True:
try:
print(next(gen))
except StopIteration:
break
In this example, we catch the StopIteration exception and break out of the loop when there are no more values to yield.
Can I use the yield keyword in a lambda function in Python?
No, you cannot use the yield keyword in a lambda function in Python. This is because lambda functions are limited to a single expression, and the yield keyword introduces a statement context. If you need to create a generator function, you’ll need to use a def statement to define a normal function.
Doctor and author focussed on leveraging machine/deep learning and image processing in medical image analysis.