else and finally blocks

RoadmapsPython

Overview

Python's exception handling includes two optional blocks: `else` and `finally`. The `else` block runs ONLY if the `try` block completes successfully without raising any exceptions. The `finally` block ALWAYS runs. It executes regardless of whether an exception occurred, whether it was caught, or even if the `try` block contains a `return` statement. The standard pattern assigns specific responsibilities to each block: - `try`: Attempts a single dangerous operation that might fail. - `except`: Handles the specific error if the operation fails. - `else`: Executes the happy-path continuation only if the operation succeeded. - `finally`: Cleans up resources unconditionally at the end. Exceptions raised inside the `else` block are not caught by the preceding `except` blocks. If your happy-path code fails, the error bubbles up: try: data = fetch_data() except NetworkError: print("Fetch failed") else: # If process() raises NetworkError, it will NOT be caught! process(data) This behavior prevents accidentally swallowing errors that occur outside the strictly dangerous operation you meant to protect.

The `finally` block guarantees that critical cleanup happens even if your code crashes halfway through. This is essential for closing database connections, closing file handles, or releasing threading locks. The `else` block improves readability by separating the code that might fail from the rest of the logic. This keeps your `try` blocks perfectly minimized, so you only catch exceptions from the exact line you expect might fail.

Where used: Ensuring database cursors are closed, Cleaning up temporary files after an upload, Releasing threading or async locks

Why learn this

Code walkthrough

def divide(a, b):
    try:
        res = a / b
    except ZeroDivisionError:
        print("Error")
    else:
        print(f"Result: {res}")
    finally:
        print("Done")

divide(10, 2)

Focus: Because the division succeeds, the `except` block is skipped, the `else` block prints the result, and the `finally` block executes last to wrap things up.

Aha moment

def test_return():
    try:
        return "Trying"
    finally:
        print("Finally runs anyway!")

print(test_return())

Prediction: What prints first: 'Trying' or 'Finally runs anyway!'?

Common guess: `'Trying'`, because the function returns immediately.

Python intercepts the `return` statement in the `try` block. It executes the `finally` block FIRST, and only after the `finally` block completes does it actually return the value `'Trying'` to the caller.

Common mistakes

Glossary

happy-path
The default scenario where everything goes exactly as planned, without any errors or unexpected problems. Example: `return content`
connection leaks
When a program opens a connection to a database but fails to close it, eventually exhausting the database's ability to handle new connections. Example: `conn.close()`

Recall questions

Understanding checks

What is the output of this function when called with `divide_and_clean(10, 2)`?

5.0 Done

The `try` block succeeds, so the `except` block is skipped and the `else` block executes, printing the result. Then, the `finally` block ALWAYS executes, printing `'Done'`.

If a `return` statement is executed inside a `try` block, does the `finally` block still run?

Yes, Python ensures the `finally` block is executed before the actual `return` takes place.

The `finally` block guarantees cleanup. Python intercepts the `return`, runs the `finally` block, and then hands the `return` value back to the caller.

Practice tasks

Guaranteed Cleanup

Modify `process_data(data)` so that it catches `ZeroDivisionError` if `100 / data` fails (printing `'Failed'`), prints `'Success'` ONLY if it succeeds, and ALWAYS prints `'Cleanup done'`.

Challenge

Safe file reader

Write `read_file(filename)`. Try to open it and read it. Handle `FileNotFoundError`. Use `else` to return the content. Use `finally` to ensure the file is closed (if it was opened). Note: you can use a mock `File` class with `.close()` for the solution.

Continue learning

Previous: try/except with specific exception types

Return to Python Roadmap