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
About to return from foo() at the bottom
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() immediately: rather it runs the finally block and then returns. I can't claim credit for noticing this: my youngest son got caught out by this behaviour and told me about it.
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 😉
No comments:
Post a Comment