Python “finally” Statement: An Ultimate Guide (with Examples)

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.

Further Reading