finally is guaranteed to execute no matter what happens in the try block — if the code succeeds, if an exception is caught by an except clause, if an exception is raised and not caught (finally still runs before the exception propagates further), and even if the try block hits a return, break, or continue. This makes it the right place for cleanup code that absolutely must happen, like closing a file or releasing a lock, regardless of how the rest of the block turned out.
1Understanding finally Block
finally is guaranteed to execute no matter what happens in the try block — if the code succeeds, if an exception is caught by an except clause, if an exception is raised and not caught (finally still runs before the exception propagates further), and even if the try block hits a return, break, or continue. This makes it the right place for cleanup code that absolutely must happen, like closing a file or releasing a lock, regardless of how the rest of the block turned out.
A return inside a finally block will silently override any return value, or even an in-flight exception, from the try/except above it — this is almost always a bug, so avoid returning from inside finally.
def process():
try:
print("Working...")
raise ValueError("Something broke")
except ValueError:
print("Handled the error")
finally:
print("Cleanup always runs")
process()2Practical Example
Here is a real-world application of finally Block showing how it is used in production Python code.
lock_acquired = False
try:
lock_acquired = True
print("Doing critical work")
finally:
if lock_acquired:
print("Releasing lock")3Best Practices
Follow these guidelines when working with finally Block:
1. Use finally for cleanup that must always happen, like closing a file, releasing a lock, or closing a network connection
2. Prefer a with statement/context manager over a manual try/finally for cleanup whenever the resource supports it, since it's less error-prone
3. Never put a return, break, or continue inside a finally — it silently discards whatever exception or return value was already in progress
Tip: A return inside a finally block will silently override any return value, or even an in-flight exception, from the try/except above it — this is almost always a bug, so avoid returning from inside finally.
def process():
try:
print("Working...")
raise ValueError("Something broke")
except ValueError:
print("Handled the error")
finally:
print("Cleanup always runs")
process()