Python What Is the Point of Finally Statement

Python What Is the Point of Finally

The point of the finally statement in Python error handling is to ensure a piece of code executes no matter what.

For example, here the something_else() function call does not get executed 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

Let’s see situations when using the finally statement makes a difference.

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. Here 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 Statement 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 Statement 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

Error Handling in Python

Python Interview Questions

Share on facebook
Share on twitter
Share on linkedin

Leave a Comment

Your email address will not be published.