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.