Consider this bit of code:-
def foo():
print("Called foo()")
try:
print("In the 'try' block")
10 / 0
except Exception as e:
print("Got an exception: ", str(e))
finally:
print("In the 'finally' block")
print("About to return from foo() at the bottom")
foo()
What do you think it will output? It probably won't come as a surprise:-
$ python3 a.py
Called foo()
In the 'try' block
Got an exception: division by zero
In the 'finally' block
Now consider this slightly variation:-
def foo():
print("Called foo()")
try:
print("In the 'try' block")
10 / 0
except Exception as e:
print("Got an exception: ", str(e))
return
print("In the 'except' block, after the 'return' statement")
finally:
print("In the 'finally' block")
print("About to return from foo() at the bottom")
foo()
Note the addition of the return statement to the except block. I would have bet money that it would behave differently: that the return in the except block would return straight out of foo(). and the finally block would not be reached. I would have lost the money:-
$ python3 a.py
Called foo()
In the 'try' block
Got an exception: division by zero
In the 'finally' block
The return statement in the except block does not exit foo(): rather it drops to the finally block. I can't claim credit for noticing this: my youngest son got caught out by this behaviour and told me about it.
One other thing to notice: in either case, if an exception occurs and is caught, foo() returns at the bottom of the finally block: the print statement at the bottom of foo() is never reached. Ofcourse, of no exception occurs, the finally block is still run and the rest of foo() runs as you would expect.
It got me to wondering if other languages behaved the same way. Let's try it in Javascript:-
function foo()
{
console.log("Called foo()")
try
{
console.log("In the 'try' block")
throw new Error("oops")
}
catch(e)
{
console.log("Got an exception: ", e)
return
console.log("In the 'catch' block, after the 'return' statement")
}
finally
{
console.log("In the 'finally' block")
}
console.log("About to return from foo() at the bottom")
}
foo()
It behaves in exactly the same way:-
$ node a.js
Called foo()
In the 'try' block
Got an exception: Error: oops
at foo (/home/eamonn/tmp/a.js:7:15)
at Object. (/home/eamonn/tmp/a.js:22:1)
at Module._compile (node:internal/modules/cjs/loader:1198:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1252:10)
at Module.load (node:internal/modules/cjs/loader:1076:32)
at Function.Module._load (node:internal/modules/cjs/loader:911:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:22:47
In the 'finally' block
Ofcourse, this is all well documented: it's just not exactly how I thought it worked. RTFM, people 😉