Is it an error to return a value in a finally clause [duplicate]
Asked Answered
W

3

8

If I try the following code, I see that the normal block return value is not returned, but the finally block return value is:

>>> def f():
...     try:
...         return "normal"
...     finally:
...         return "finally"
... 
>>> f()
'finally'

A more advanced example is to call a function in each return statement:

In that situation, I can see that:

  • In the normal block, the show function is evaluated (but not return),
  • In the finally block, the show function is evaluated and returned:
>>> def show(x):
...     print(x)
...     return x
... 
>>> def g():
...     try:
...         return show("normal")
...     finally:
...         return show("finally")
... 
>>> g()
normal
finally
'finally'

Is it a good practice the have a return statement in a finally clause? Or, is it a potential error (which should be detected by a code analysis tools or a code review)?

EDIT

Another example with an exception:

>>> def f():
...     try:
...         raise ValueError("bad")
...     finally:
...         return "good"
... 
>>> f()
'good'

Weird!

Wellrounded answered 15/10, 2019 at 11:27 Comment(3)
I think the documentation explains some part of it: docs.python.org/3/tutorial/… It says the following "If a finally clause includes a return statement, the finally clause’s return statement will execute before, and instead of, the return statement in a try clause."Elope
Weird Try-Except-Else-Finally behavior with Return statementsLitton
cpython has a funky unit test github.com/python/cpython/blob/…Stramonium
D
3

IMHO, having a return in a finally clause is bad practice if there is a return statement in the related try or except blocks.

try:
    # lots of spaghetti code
    return fancy_expression_with_side_effects
except AllKindsOfError:
    # lots of alternative spaghetti code
finally:
    # many a mouse wheel spin down the module
    # lots of clean up
    return eternal_return_value

While this would constitute valid Python, it really should't. The first return statement will partially execute: you will observe the side effects of evaluating fancy_expression_with_side_effects (try return print('foo') there) and it will still not return that expression's value. I have once scratched my head for a couple of hours in that exact situation.

If, however, the return statement in the finally is the only return statement, one will be able to easily follow the step-by-step execution flow in a simple expected manner and I don't see too much fault in it, but would stilll be very careful: In many software projects, you might be the senior Python guy who knows such stuff, but what guarantee do you have that no one else will add a return statement elsewhere later on?

Dalhousie answered 15/10, 2019 at 12:10 Comment(0)
D
1

It would make it easier to understand if you run the script while including prints. It shows that it actually goes inside the try block performs all operations (in fact almost returns), only the finally part overrides the first return statement.

>>> def f():
...     try:
...             print("try")
...             return "try"
...     finally:
...             print("finally")
...             return "finally"
...
>>> f()
try
finally
'finally'

Is it a good practice? I think sometimes this is a necessity and i don't see anything wrong about it. The finally block when executed also releases resources and other things so i don't see a reason why this is wrong. (I wouldn't say this is a good practice but there is nothing wrong about it.)

Disputant answered 15/10, 2019 at 11:40 Comment(1)
I would say it is bad practice if there is a return statement elsewhere. You will confuse the heck out of yourself and coworkers trying to debug code where return statements in the normal flow are reached without error, but magically not executedDalhousie
A
0

In my opinion, it is not the best practice to have return statement in a finally clause, since the value is going to be returned is always the one in the finally clause.

It may be best practice in case you want to always return the same value no mather what the function does.

The evaluating occurs because you run this code in python shell.

In a return case , i would say the best practice is to use try and except only.

def myfunc(x):
    try:
        return x / 0

    except:
        return x

a = myfunc(20)
print(a)
Actuate answered 15/10, 2019 at 11:49 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.