In Python, the finally statement is helpful with error handling to ensure code executes.
For example, here the something_else() call does not run because it is not in an finally block:
try: something() except: return None something_else() # This does not get executed
But by placing it inside a finally block, it gets executed no matter what:
try: something() except: return None finally: something_else() # Always gets executed
This is a comprehensive guide to the finally statement in Python. You’ll learn what the finally keyword does and how you can use it in error handling. Besides, you will learn how the finally keyword works with continue and break statements.
Early Return with “finally” Statement
If your error handling code returns a value in the except block, the code that comes after that does not execute.
For example, let’s return a value from the function if an exception occurs.
def without_finally():
try:
print(x)
except:
print("There was an error")
return None
print("Yay")
without_finally()
As we tried to print an undefined value x, there was an exception. Thus the function returned a value and print("Yay") was never run.
There was an error
As you can see, "Yay" does not get printed out because the function exits before.
But if we place the print function call into a finally block, it indeed gets executed.
def with_finally():
try:
print(x)
except:
print("There was an error")
return None
finally:
print("Yay")
with_finally()
Output:
There was an error Yay
So even though we return from the function inside the except block, the code in the finally block runs.
This is useful if you want to run cleanup code before exiting.
For example, you could close opened files in the finally block.
An Unexpected Error
In error handling, we expect certain types of errors in the except block(s).
But sometimes the error could be something that the except block is not prepared for.
When this happens, the finally block still gets executed.
To demonstrate, let’s try to write to a file. The code inside the try block throws an error unrelated to file writing:
file = open("example.txt", "w")
try:
print(x)
file.write("Test")
print("Writing to file.")
except IOError:
print("Could not write to file.")
else:
print("Write successful.")
finally:
file.close()
print("File closed.")
Output:
File closed.
Traceback (most recent call last):
File "example.py", line 4, in <module>
print(x)
NameError: name 'x' is not defined
The except block did not run because we got a different kind of error than expected.
But still, the finally block was executed before propagating the error to the caller.
This would have been different without the finally block:
file = open("example.txt", "w")
try:
print(x)
file.write("Test")
print("Writing to file.")
except IOError:
print("Could not write to file.")
else:
print("Write successful.")
file.close()
print("File closed.")
Output:
Traceback (most recent call last):
File "example.py", line 4, in <module>
print(x)
NameError: name 'x' is not defined
As you can see, the file would not be closed, and the final message would not have been logged.
Continue with “finally” Statement
In Python, the continue statement skips the “rest of the iteration” in a loop and continues to the next one.
If you use a continue statement in an error-handling code in a loop, any code after continue does not get executed.
For example:
def without_finally():
for i in range(5):
try:
print(x)
except:
print("There was an error")
continue
print("Yay")
without_finally()
Output:
There was an error There was an error There was an error There was an error There was an error
Here “Yay” does not get printed out.
This is because the continue statement already jumped to the next iteration.
You can fix this by using the finally statement:
def with_finally():
for i in range(5):
try:
print(x)
except:
print("There was an error")
continue
finally:
print("Yay")
with_finally()
Output:
There was an error Yay There was an error Yay There was an error Yay There was an error Yay There was an error Yay
Break with “finally” Statement
The break statement exits a loop in Python.
If you do error handling in a loop and you break the loop, the code after break will not be executed.
For example, let’s break a loop on an exception:
def without_finally():
for i in range(5):
try:
print(x)
except:
print("There was an error")
break
print("Yay")
without_finally()
Output:
There was an error
Here, the “Yay” was not printed into the console, because the loop was escaped beforehand.
Let’s use the finally block to ensure the “Yay” gets printed:
def with_finally():
for i in range(5):
try:
print(x)
except:
print("There was an error")
break
finally:
print("Yay")
with_finally()
Output:
There was an error Yay
Except Throws Another Exception
If you are not using finally statement, and there is an error in the except block, everything after that is not going to be executed.
For example:
def without_finally():
try:
print(x)
except:
print("There was an error")
print(y)
print("Yay")
without_finally()
Output:
There was an error
Traceback (most recent call last):
File "example.py", line 3, in without_finally
print(x)
NameError: name 'x' is not defined
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "example.py", line 9, in <module>
without_finally()
File "example.py", line 6, in without_finally
print(y)
NameError: name 'y' is not defined
This only prints “There was an error” before throwing the error. It does not print “Yay” after the error handling structure.
But if you used a finally block, the print("Yay") would also be executed.
def with_finally():
try:
print(x)
except:
print("There was an error")
print(y)
finally:
print("Yay")
with_finally()
Output:
There was an error
Yay
Traceback (most recent call last):
File "example.py", line 3, in with_finally
print(x)
NameError: name 'x' is not defined
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "example.py", line 10, in <module>
with_finally()
File "example.py", line 6, in with_finally
print(y)
NameError: name 'y' is not defined
Conclusion
Today you learned what is the point of the finally statement in Python error handling.
The finally statement is always executed no matter what. This is useful if you need to run cleanup code regardless of what happens.
For example, as a cleanup, you should always close a file no matter what.
I hope you find it useful.
Happy coding.