Python function with try, except, finally, and return

As we have observed in instructional content, technical literature, and official Python documentation, a return statement, when executed, terminates execution of the function that contains it, and delivers a value to the statement that called the function. Literature on Python also offers much information on handling exceptions.

See:

For practice, but at the risk of sowing confusion, let’s take a look at the following code:

# A return statement terminates execution of a function,
# and delivers a value to the calling statement.

# Which return statements will execute here,
# and what will be the output?

def fun(num, den):
  # How many of the return statements in this function will execute?
  print("fun!")
  try:
    return divide(num, den)
  except:
    return eggs()
  finally:
    return spam()

def divide(num, den):
  print("divide!")
  return num / den
  
def eggs():
  print("eggs!")
  return "eggs function return value"

def spam():
  print("spam!")
  return "spam function return value"

print(fun(42, 0))

Output:

fun!
divide!
eggs!
spam!
spam function return value

For practice, copy it, execute it, modify it, and experiment with it, using Python 3. Can you explain what happens? In particular, which return statements executed, and why?

Feel free to post explanations, questions, and your modifications of the code.

9 Likes

I think I got it figured out:

Spoiler Alert

When the fun() function is called, "fun!" is printed,
The try attempts to return the value of divide, which prints "divide!", but the return inside divide() fails due to a division by zero error.

Because of the error the except attempts to return the value of eggs, which prints "eggs!".
Here is were I am not entirely certain what happens.

From what I can tell a return inside a finally will override a return elsewhere. So it returns the value of spam(), which prints "spam!" and then returns "spam function return value". This is then returned to the print() the first called fun() and it is printed to the console.


What is interesting to me is that a finally seems to be able to both delay and override a return statement.

Here the finally delays a return so it can print before the function ends:

def add(n1, n2):
  try:
    return n1 + n2
  except:
    return "there was an error"
  finally:
    print("finally is doing somethin'")

print(add(1, 2))

# prints:
# finally is doing somethin'
# 3

And here a finally overrides the return altogether` and instead returns its own value:

def add(n1, n2):
  try:
    return n1 + n2
  except:
    return "there was an error"
  finally:
    return "finally is doing somethin'"


print(add(1, 2))

# prints:
# finally is doing somethin'
3 Likes

Yes, this statement within the except block begins to execute:

    return eggs()

In order for it to execute, eggs() must first be evaluated prior to the return action. We can verify that the eggs function was called by noting this in the output:

eggs!

Consistent with the quote above, the finally block executes, and the return statement within it terminates execution of the fun function, which prevents the return statement within the except block from completing execution.

Thanks for the two versions of the add function in your post. They illustrate, quite well, the points you made.

Others who read this, please feel free to comment, ask questions, and provide additional code examples.

Perhaps we can also consider whether the code in the original post is consistent with
PEP 20 – The Zen of Python. :laughing:

Edited on August 26, 2020 to add the following:

There’s no need to tag your posted explanations or code as spoilers. Whether or not to do so is entirely up to you.

1 Like