finally in Python: code that runs no matter what

The finally block runs in every case, with or without an error, and even after a return: it is where you close what was opened earlier.
5 min read
Believemy logo

Definition

A program that opens something has to close it again: a file, a database connection, a lock, a temporary folder. The trouble is that the closing line always comes after the work, and an error raised during that work stops everything before you reach it. The resource stays open, and nobody notices until the day the server starts refusing new connections.

finally answers exactly that problem. This block ends a try structure, and Python commits to running it in every case: the work went through, an exception was caught by an except, an exception was caught by nobody, or the function left earlier than planned through a return. No other block in the language offers that guarantee.

PYTHON
connection = open_connection()
try:
    connection.execute(query)
except TimeoutError:
    log("Too slow")
finally:
    connection.close()   # called whether the query goes through or not

The connection is handed back in all three possible scenarios: the query succeeds, it times out and the except catches it, or it fails for an unforeseen reason. Writing connection.close() one line below, outside the structure, would cover the first two cases but not the third: the exception would travel up straight away and take the closing line with it.

That is all finally knows how to do, and it changes the way you write: cleanup moves into a zone that nothing can skip, and you stop wondering which paths the program might escape through.


It runs even after a return

Here is the behaviour that surprises people most, and it is also the one that makes the block genuinely useful. It is tempting to picture a return ending the function on the spot. That is not what happens.

PYTHON
def read(path):
    handle = open(path)
    try:
        return handle.read()   # 1. the value is read, then set aside
    finally:
        handle.close()         # 2. cleanup happens next
                               # 3. and the value leaves only after that

Python first evaluates the expression following the return, sets the result aside, runs the finally, and hands the value back at the very end. The question that follows is a fair one: can the cleanup damage what is about to be returned? No, the reading is already over, and closing the file afterwards takes nothing away from the text just pulled out of it.

The same mechanism applies to break and continue inside a loop: the exit is prepared, the finally slots in, then the exit happens.

Warning

Never put a return inside the finally itself. It overwrites the value prepared by the try, and above all it makes a live exception disappear: the error shows up nowhere any more, not in the logs and not in the traceback, and the function quietly returns a wrong result. A raise or a break written there causes the same silent erasure.


What with does in its place

The try and finally pair shows up so often around files and connections that Python ended up wrapping it in a dedicated form: the context manager, used with the with keyword.

PYTHON
# The with already holds a finally, written once and for all inside open()
with open("data.csv") as handle:
    content = handle.read()

The two forms are not competing: the with triggers a hidden finally, supplied by the object itself. As soon as the thing you handle knows how to close itself, prefer that form, shorter and impossible to forget.

finally takes over for everything that is not a closable object, and those cases stay common: a counter to reset, a global setting to restore, a closing line to write to the logs with logging, a stopwatch to stop. No context manager exists for them, and the explicit block remains the right tool.


The exact order of execution

When a try brings several blocks together, saying from memory which one runs before which quickly becomes guesswork. The table below gives the sequence for the four situations you will meet, each row reading left to right as a timeline.

SituationWhat runs, in order
No errortry, then else, then finally
Caught errortry up to the error, then except, then finally
Uncaught errortry up to the error, then finally, then the error travels up
Exit through returntry up to the return, then finally, then the value leaves

Remember the last row above all, because it is the one that makes the difference once you are in production: cleanup happens before the caller receives anything at all. Returning the contents of a file from a try while closing it in the finally is therefore perfectly safe.

One point often missing from explanations: an error raised inside the except, while you handle the first one, also triggers the finally before travelling up. The rescue block does not escape the rule either.


Frequently asked questions

Question

Does finally run if the program really crashes?

On an uncaught exception, yes: the block runs in full, then the exception carries on up the stack until the traceback is printed. The only situations that prevent it fall outside the language: a process killed by the operating system, a power cut, or a direct call to os._exit(). No Python code can intercept those.

Question

Can there be a finally without an except?

Yes, a try followed directly by a finally is perfectly valid, and that form is in fact very common. It says something precise: I do not claim to handle this error, I let it travel up to the code that will, but I insist on tidying up before it goes.

Question

How does it differ from the try else block?

The else runs only when the try went through without a single error, whereas finally runs in every case. The first carries on with work that depends on success, the second releases what was taken. The two sit together very well in the same structure, with the else always running before the finally.

Related terms

Discover our python glossary

Browse the terms and definitions most commonly used in development with Python.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.