So I ran into an interesting issue today with try-finally and a return statement in Python.
I was creating a simple if-else on a library that was prone to erroring, so I needed to put it in a try-finally to make sure clean up always happened:
def get_error_prone_choice(value):
try:
if is_a_good_choice(value):
return error_prone_function(True)
else:
return another_error_prone_function(False)
finally:
clean_up()
Here’s where the multiple exits from a function that Python allows adds some confusion. When does clean_up()
happen? I needed to make sure that clean_up
happened before it returned the value or bad things would happen (specifically a non-garbage collected object would start to accumulate from the inspect module).
It turns out the finally
clause is called at the last possible moment when leaving the try-finally section even when leaving the function, which means I’m fine to use it as it is. However, returning from a finally
AND from the main try
statement can get confusing quickly:
def get_error_prone_choice(value):
try:
return error_prone_function(True)
finally:
return clean_up()
This will result in error_prone_function
to be evaluated, then the result of clean_up()
to be returned! The finally
is always called at the last possible moment, meaning the return value is first set to the result from error_prone_function
and then overwritten to the result from clean_up()
.