Sunday 10 May 2020

Difference between yield and return in python

Background

If you have been using Python you would have come across return and yield statements. Both are used to return something from a function. Though both of them are used to return something from the function both serve different purposes. In this post, I will try to explain what those are.

I use Jupyter notebook for running python code snippets. To see how you can install it refer to my earlier post (link in the Related Sections at the end of this post).

Understanding return in Python

Let's try to understand returns first as that's the simplest. The return keyword is used is a similar fashion in multiple programming languages. It is used to return a value to its caller.

A function can have multiple return statements but only the 1st one encountered during its execution flow will be executed and the corresponding value will be returned to the called. No code after the return statement will be executed (dead code) - the method with return statement exists. The return statement is generally the last statement in a function but it could be before as well if we want to skip subsequent code based on a certain condition. 

Consider the following example:

def is_even(num):
    if num is None:
        return False
    elif num%2 == 0:
        return True
    else:
        return False
    
print(is_even(2))
print(is_even(3))
print(is_even(None))

The output is:
True
False
False


As you can see the function is_even has multiple return statements and exactly one will get executed for a single execution call based on the conditions. You could also rewrite it as :

def is_even(num):
    is_even=True
    if num is None or num%2 != 0:
        is_even = False
    return is_even
    
print(is_even(2))
print(is_even(3))
print(is_even(None))


This is a slightly better version than the previous one. we just have one return statement and less code.


Understanding yield in Python


Yield statement also returns the value to the caller but it retains the state. When you call the function again it resumes where it left off (last yield statement). This enabled code to generate a series of data when needed without generating all at once.

Such structures that generate a series of data are called generators in python and yield keywords are used to create generators. Whenever generators need to produce a value they do it using the yield keyword. Consider the following example:
def get_even():
    i=0
    while True:
        i = i + 2
        yield i
    
test = get_even()
print(next(test))
print(next(test))
print(next(test))


This outputs:
2
4
6

As you can see this is a forever going generator. It will keep on generating the sequence. If you do something like below, it will go in an infinite loop:

def get_even():
    i=0
    while True:
        i = i + 2
        yield i
   
test = get_even()
for evennum in test:
    print(evennum)


This outputs an infinite series of even numbers starting from 2. You will have to manually kill the process as it goes into an infinite loop.

If there are limited field statements in the function, the generator will run that many times. If you try to run a generator after that it will raise an Exception.

def get_even():
    i=0
    i = i + 2
    yield i
    i = i + 2
    yield i 

test = get_even()
for evennum in test:
    print(evennum)
next(test)


Output:
2
4
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-40-ef2477e0fee5> in <module>
     10 for evennum in test:
     11     print(evennum)
---> 12 next(test)

StopIteration: 

You can have return statements in a generator as well which simply signifies the end of that generator. No yield statement after the return statement will be respected. Consider the following example:
def get_even():
    i=0
    i = i + 2
    yield i
    return
    i = i + 2
    yield i

    
test = get_even()
for evennum in test:
    print(evennum)
next(test)


This will print:

2
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-41-554cedfc9db7> in <module>
     11 for evennum in test:
     12     print(evennum)
---> 13 next(test)

StopIteration: 


As you can see it encountered 1st yield and returned back 2. In the next call, it saw a return statement and terminated the generator. So, calling it again is going to raise an Exception as we saw above. Having return and yield statement was not allowed in python2 but it's allowed in python3 and it simply means the end of the generator.


Summarizing the difference

  • Return statements terminate the execution of the method and return the value to the caller whereas yield returns the value to the caller but retains the current state so that the same method can be called again. 
  • The yield keyword is used in Python generators. A generator is a special function that returns a generator object to the caller instead of the actual value. 
  • Generators save memory as the new value is generated only when the generator is called. If the same thing you had to do with the return, you would need to compute the series, store all in an array and return the array once.
  • As generators with the yield keyword resume the execution all local variables are retained whereas in case of return they are destroyed.


Related Links



t> UA-39527780-1 back to top