Weird Try-Except-Else-Finally Behavior with Return Statements

Weird Try-Except-Else-Finally behavior with Return statements

Because finally statements are guaranteed to be executed (well, presuming no power outage or anything outside of Python's control). This means that before the function can return, it must run the finally block, which returns a different value.

The Python docs state:

When a return, break or continue statement is executed in the try suite of a try…finally statement, the finally clause is also executed ‘on the way out.’

The return value of a function is determined by the last return statement executed. Since the finally clause always executes, a return statement executed in the finally clause will always be the last one executed:

This means that when you try to return, the finally block is called, returning it's value, rather than the one that you would have had.

Python try finally block returns

From the Python documentation

A finally clause is always executed before leaving the try statement, whether an exception has occurred or not. When an exception has occurred in the try clause and has not been handled by an except clause (or it has occurred in a except or else clause), it is re-raised after the finally clause has been executed. The finally clause is also executed “on the way out” when any other clause of the try statement is left via a break, continue or return statement. A more complicated example (having except and finally clauses in the same try statement works as of Python 2.5):

So once the try/except block is left using return, which would set the return value to given - finally blocks will always execute, and should be used to free resources etc. while using there another return - overwrites the original one.

In your particular case, func1() return 2 and func2() return 3, as these are values returned in the finally blocks.

Why 'try/finally' interacts strangely with 'return' in Python?

Because finally is a cleaning up action that is always excuted if added in a try, except,else, finally ;)

You can read Python 3 documentation’s page on Error handlings here:https://docs.python.org/3/tutorial/errors.html

Section: 8.6. Defining Clean-up Actions

Is it an error to return a value in a finally clause

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?

Why is Finally executed after return statement?

https://docs.python.org/2/tutorial/errors.html

"A finally clause is always executed before leaving the try
statement, whether an exception has occurred or not. When an exception
has occurred in the try clause and has not been handled by an except
clause (or it has occurred in a except or else clause), it is
re-raised after the finally clause has been executed. The finally
clause is also executed “on the way out” when any other clause of the
try statement is left via a break, continue or return statement.

try / else with return in try block

http://docs.python.org/reference/compound_stmts.html#the-try-statement

The optional else clause is executed if and when control flows off the
end of the try clause.

Currently, control “flows off the end” except in the case of an
exception or the execution of a return, continue, or break statement.

Using try+finally without except never generates any error

You can find documented in the section about the try statement:

If the finally clause executes a return, break or continue statement, the saved exception is discarded.

Of course, the fact that it's a documented behavior does not entirely explain the reasoning, so I offer this: a function can only exit in one of two ways, by returning a value or raising an exception. It can not do both.

Since the finally block is commonly used as a cleanup handler, it makes sense for the return to take priority here. You do have the chance to re-raise any exceptions within finally, simply by not using a return statement.



Related Topics



Leave a reply



Submit