Python Exception Handling: Controlling Cleanup with else and finally

Python’s exception handling syntax (try-except) has two lesser-known but very important optional clauses: else and finally. By combining these appropriately, you can clearly define “processing to execute only when no error occurs” and “cleanup processing to execute regardless of errors (like releasing resources).”

This article explains the complete syntax of try-except-else-finally and the role of each block.


目次

Complete Syntax of Exception Handling

Exception handling consists of up to four blocks.

try:
    # Process that might raise an exception
except ExceptionClass:
    # Process when an exception occurs
else:
    # Process when NO exception occurs
finally:
    # Process that ALWAYS executes at the end, regardless of exceptions

else Clause: Processing on Success

The else block executes only if no exception occurred inside the try block. You might think, “Why not just write it at the end of the try block?” The benefit is keeping the try block minimal. By putting only “code that might raise an exception” in the try block and putting “safe processing using the result” in else, you reduce the risk of accidentally catching unintended exceptions with except.

finally Clause: Cleanup Processing

The finally block always executes at the end, whether an exception occurred or not. Even if a return statement is executed inside try or except, the finally block is passed through before the function exits. Therefore, it is ideal for “cleanup” processing like closing files, disconnecting database connections, or deleting temporary data.


Practical Code Example

As a concrete example, let’s create a function that simulates data loading from an external file.

  • try: Attempt to load data (Potential error).
  • except: Handle loading errors.
  • else: Process and display loaded data (Execute if no error).
  • finally: Disconnect connection (Always execute).
def process_file_data(filename):
    print(f"--- Start processing '{filename}' ---")
    
    # Mock data store
    dummy_files = {
        "data.txt": [10, 20, 30],
        "empty.txt": []
    }

    try:
        # 1. Load data (Risky process)
        if filename not in dummy_files:
            raise FileNotFoundError(f"File '{filename}' not found.")
        
        data = dummy_files[filename]
        
        # Calculation (Potential ZeroDivisionError if empty)
        average = sum(data) / len(data)

    except FileNotFoundError as e:
        # 2. Error handling if file missing
        print(f"[Error] File Error: {e}")
    
    except ZeroDivisionError:
        # 2. Error handling if data is empty
        print("[Error] Calc Error: Cannot calculate average of empty data.")

    else:
        # 3. Processing on success
        # Even if a new error occurs here, it won't be caught by the except blocks above (Safe)
        print(f"[Success] Average calculated: {average:.2f}")

    finally:
        # 4. Cleanup (Always executes)
        print("[Cleanup] File connection disconnected.")
        print("--------------------------------\n")

# --- Execution Test ---

# Case 1: Success
process_file_data("data.txt")

# Case 2: File Not Found Error
process_file_data("unknown.csv")

# Case 3: Calculation Error
process_file_data("empty.txt")

Output:

--- Start processing 'data.txt' ---
[Success] Average calculated: 20.00
[Cleanup] File connection disconnected.
--------------------------------

--- Start processing 'unknown.csv' ---
[Error] File Error: File 'unknown.csv' not found.
[Cleanup] File connection disconnected.
--------------------------------

--- Start processing 'empty.txt' ---
[Error] Calc Error: Cannot calculate average of empty data.
[Cleanup] File connection disconnected.
--------------------------------

Key Behavior Points

  • Success (data.txt): Executed in order try -> else -> finally.
  • Failure (unknown.csv, empty.txt): Executed in order try -> except -> finally.
  • Regardless of the outcome, the [Cleanup] message in the finally block was always output.

Summary

  • else: Executed when no exception occurs. Use it to narrow down the try block to only code that needs exception monitoring.
  • finally: Always executed at the end, regardless of exceptions. Use it to guarantee cleanup processing like releasing resources.

By mastering these, you can write robust programs that are resistant to errors and free from resource leaks.

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次