Python finally Block

In the last lesson you learned how to catch Multiple Exceptions in one place. Now there is one more piece to the try block. Sometimes you open something, like a file or a connection. Then you need to close it no matter what happens. That closing step is what the finally block is for.

🤔 Why We Need finally

Here is the pain. You open a file to work with it. Then partway through, an error happens. Your code jumps to the except block. The line that closes the file never runs. So the file stays open. Do that enough times and your program holds on to things it should have let go of.

You might think, “I will just close it at the end of the try block.” But if an error fires before that line, you never reach it. And if you close it inside except too, now you are writing the same cleanup line in two places.

The fix is simple. The finally block always runs, whether an error happened or not. So you put your cleanup there once. Then it runs every single time.

🧩 What finally Is

Think of finally like locking your front door when you leave the house. It does not matter if your day went well or badly. On the way out, you lock the door. Every time.

That is finally. The try part is your day. The except part is when something goes wrong. And finally is the door you lock on the way out, no matter how the day went.

The shape looks like this:

try:
# code that might fail
except SomeError:
# runs only if that error happened
finally:
# runs every time, error or not

The try and finally are the important pair here. The except is optional for the rule we care about. The promise is simple. Once Python enters the try, the finally will run before it leaves.

✅ When No Error Happens

Let’s start with the happy case. Nothing goes wrong. We want to see the order in which the lines run.

This small program does some work, hits no error, and then reaches finally.

try:
print("1. Inside try")
result = 10 / 2
print("2. Work done, result is", result)
except ZeroDivisionError:
print("This only runs if we divide by zero")
finally:
print("3. finally always runs")

Walking through it line by line:

  • Python enters the try and prints 1. Inside try.
  • The division works fine, so it prints 2. Work done, result is 5.0.
  • No error happened, so the except block is skipped completely.
  • On the way out, finally runs and prints 3. finally always runs.

So the output is:

Output

1. Inside try
2. Work done, result is 5.0
3. finally always runs

See how finally ran at the end even though nothing went wrong? That is the whole point. It does not wait for an error. It just runs.

⚠️ When An Error Happens

Now the other case. Something does go wrong. We want to check that finally still runs.

This is the same shape. But this time we divide by zero on purpose, so an error fires.

try:
print("1. Inside try")
result = 10 / 0
print("This line never runs")
except ZeroDivisionError:
print("2. Caught the error")
finally:
print("3. finally always runs")

Walking through it line by line:

  • Python enters the try and prints 1. Inside try.
  • The division by zero fails right away, so the next print is skipped.
  • Python jumps to the except block and prints 2. Caught the error.
  • Then finally runs and prints 3. finally always runs.

So the output is:

Output

1. Inside try
2. Caught the error
3. finally always runs

Notice the line print("This line never runs") never printed. The error skipped it. But finally still ran at the end. Error or no error, you get the same last line.

🧹 A Real Cleanup Example

Now the reason finally exists in real code. Closing things.

Say Alex opens a file to write to it. While working, something could go wrong. We still want the file closed. So we put close() in finally.

This opens a file, writes to it, and closes it in finally so the file is closed even if the work fails.

file = open("notes.txt", "w")
try:
print("Writing to the file")
file.write("Hello from Alex")
# imagine an error could happen here
finally:
file.close()
print("File closed safely")

Walking through it:

  • We open the file and start the try.
  • We write to it and print Writing to the file.
  • Whether the write succeeds or an error happens, finally runs.
  • finally closes the file and prints File closed safely.

So the output is:

Output

Writing to the file
File closed safely

The key idea is that file.close() is now guaranteed. You do not have to hope the code reached it. The finally block makes sure of it.

Notice one thing about where we put open(). It sits before the try, not inside it. That matters. If open() itself fails, then file was never created, and there is nothing to close. By opening first, we only reach the try once we truly have a file in hand.

🔀 The Optional else Block

There is one more friend here. The else block. It runs only when the try finished with no exception. So else is for “everything went fine” code. And finally is for “run this no matter what” code.

The full order, when all four are present, is try, then else if no error, and finally last.

This shows all four blocks together so you can see when each one runs.

try:
print("1. Trying")
value = int("42")
except ValueError:
print("Could not convert")
else:
print("2. No error, so else runs")
finally:
print("3. finally runs last")

Here is what happens:

  • The try runs and converts "42" to the number 42 with no error.
  • Because there was no error, Python runs the else block.
  • Then finally runs at the very end.

So the output is:

Output

1. Trying
2. No error, so else runs
3. finally runs last

A simple way to remember the difference. else runs only on success, while finally runs every time.

Here is the same idea as a quick table:

Block When it runs
try Always, this is the code you are watching
except Only when a matching error happens
else Only when no error happened
finally Every time, error or not

⚠️ Common Mistakes

A few things trip people up with finally:

  • Putting cleanup inside try instead of finally. If an error fires first, the cleanup line is skipped.
# ❌ Avoid: close() may never run if read() fails
file = open("data.txt")
try:
data = file.read()
file.close()
except ValueError:
print("Bad data")
# ✅ Good: close() runs no matter what
file = open("data.txt")
try:
data = file.read()
finally:
file.close()

Notice that open() sits before the try in both snippets. So the only difference is where close() lives. In the first one close() is inside the try, so an error can skip it. In the second one close() is in finally, so it always runs.

  • Expecting finally to be skipped when there is no error. It is not optional. If Python entered the try, finally will run.

  • Confusing else and finally. The else block runs only on success. The finally block runs every time.

  • Returning from inside try and thinking that skips finally. Even a return in the try will still run finally first, before the function actually returns.

✅ Best Practices

Some simple habits that keep this clean:

  • Put only cleanup in finally, like closing files, closing connections, or releasing a lock.
  • Keep the finally block short. It is not the place for new logic that might fail.
  • Use else for the “it worked” follow-up code so your try stays small and only holds the line that might fail.
  • For files, prefer a with statement when you can. It closes the file for you, so you often do not need a manual finally at all.

Tip

The with statement is the cleaner everyday choice for files because it handles closing for you. But knowing finally still matters. Not every resource supports with, and you will read plenty of code that uses finally directly.

🧩 What You’ve Learned

A quick recap of what you can now do:

  • ✅ You know the finally block always runs, whether an error happened or not.
  • ✅ You can trace the order of try, except, and finally in both the success case and the error case.
  • ✅ You can use finally to close files and release resources safely.
  • ✅ You know the else block runs only when no exception happened.
  • ✅ You know when to reach for with instead of a manual finally.

Check Your Knowledge

Test what you learned. Pick an answer for each question, then click Check.

  1. 1

    When does the finally block run?

    Why: The finally block always runs once Python has entered the try, no matter what happens.

  2. 2

    What is the finally block mainly used for?

    Why: finally is the place for cleanup that must happen every time, like closing a file or releasing a resource.

  3. 3

    When does the else block run?

    Why: The else block runs only when the try finished with no exception.

  4. 4

    If all four blocks are present and no error happens, what is the run order?

    Why: With no error the except is skipped, so it runs try, then else, then finally last.

🚀 What’s Next?

You can now clean up safely after your code, even when things go wrong. Next you will learn how to make your own errors happen on purpose when something is not right.

raise Statement

Share & Connect