Sometimes, regardless of whether an error occurred or not, there are actions you absolutely need to perform. Think about tasks like closing a file you opened, releasing a network connection, or cleaning up temporary resources. These cleanup actions are important to prevent resource leaks or corrupted data. Python provides the finally
block precisely for this purpose: it guarantees execution.
The finally
clause is added to a try...except
structure. The code inside the finally
block will always run, no matter what happens in the try
and except
blocks.
try
block finishes without any exceptions, the finally
block runs after the try
block (and after the else
block, if present).try
block and is caught by an except
block, the finally
block runs after the except
block has finished.try
block but is not caught by any except
block, the finally
block still runs before Python propagates the exception up the call stack (which usually results in the program stopping and displaying an error message).try
or except
block executes a return
, break
, or continue
statement, the finally
block will execute before control actually transfers out.You can use finally
with try
alone, or together with except
and optional else
blocks:
# Example 1: try...finally
try:
# Code that might need cleanup
print("Attempting some operation...")
# result = 10 / 0 # Uncomment to simulate an error
finally:
print("This finally block always executes for cleanup.")
# Example 2: try...except...finally
try:
print("\nAttempting file operation...")
file = open("my_temporary_file.txt", "w")
file.write("Writing some data.\n")
# Simulate an error during processing
# int("not a number")
print("File write successful (potentially).")
except ValueError:
print("Caught a ValueError!")
finally:
print("Executing finally block now.")
# Ensure the file is closed, even if an error occurred
if 'file' in locals() and not file.closed:
file.close()
print("File closed.")
else:
print("File object doesn't exist or was already closed.")
finally
?The primary use case is resource management. When you acquire a resource (like opening a file), you often need to release it later. If an error happens after acquiring the resource but before releasing it, your program might leak the resource. Placing the release code in a finally
block ensures it runs.
Consider the file example above. We open my_temporary_file.txt
for writing.
try
block completes successfully. The finally
block runs, closing the file.int("not a number")
, a ValueError
would occur. The except ValueError
block would run. Afterward, the finally
block would still run, closing the file.result = 10 / 0
, a ZeroDivisionError
would occur. Since there's no except ZeroDivisionError
block, the exception is uncaught. However, the finally
block would still execute (closing the file) before the program terminates due to the unhandled ZeroDivisionError
.finally
vs. with
statementYou might notice that the file closing example seems similar to using the with
statement, which we saw in the chapter on file handling:
try:
with open("another_temp_file.txt", "w") as file:
print("\nAttempting file operation using 'with'...")
file.write("Data written using with statement.\n")
# Simulate an error
# result = 1 / 0
print("File write successful (using 'with').")
print("Exited the 'with' block.")
except ZeroDivisionError:
print("Caught ZeroDivisionError outside 'with'.")
print("Code continues after 'with' block or exception handling.")
The with
statement is essentially syntactic sugar for common try...finally
cleanup patterns, especially for objects that have specific setup (__enter__
) and teardown (__exit__
) methods, like file objects. When you use with open(...)
, Python automatically ensures the file's close()
method is called when the block is exited, whether normally or due to an exception. For file handling and similar resource management scenarios supported by context managers, using with
is generally preferred as it's more concise and less error-prone than manually writing try...finally
blocks.
However, the finally
block remains a fundamental construct for guaranteed execution in situations where the with
statement isn't applicable or when you need more complex cleanup logic than simple resource release. It's the underlying mechanism that provides the guarantee of execution needed for robust error handling and resource management.
© 2025 ApX Machine Learning