Pythonの例外処理:elseとfinallyによる終了処理の制御と使い分け

Pythonの例外処理構文(try-except)には、あまり知られていないものの、非常に重要な役割を持つ2つのオプション、elsefinallyが存在します。

これらを適切に組み合わせることで、「エラーが起きなかったときだけ実行したい処理」や、「エラーの有無にかかわらず必ず実行したい終了処理(リソースの解放など)」を明確に記述できます。

この記事では、try-except-else-finally の完全な構文と、それぞれのブロックの役割について解説します。

目次

例外処理の完全な構文

例外処理の構文は、最大で4つのブロックで構成されます。

try:
    # 例外が発生する可能性のある処理
except 例外クラス:
    # 例外が発生した場合の処理
else:
    # 例外が発生しなかった場合の処理
finally:
    # 例外の有無にかかわらず、最後に必ず実行される処理

else 節:正常終了時の処理

else ブロックは、try ブロック内で例外が発生しなかった場合のみ実行されます。

「それなら try ブロックの最後に書けばいいのでは?」と思われるかもしれませんが、else に分けることには明確なメリットがあります。それは、try ブロックの中身を最小限にできる点です。

try ブロック内には「例外が発生する可能性があるコード」だけを記述し、「その結果を使って行う安全な処理」は else に記述することで、意図しない例外まで except で捕捉してしまうリスクを減らすことができます。

finally 節:終了処理(クリーンアップ)

finally ブロックは、例外が発生してもしなくても、必ず最後に実行されます

たとえ tryexcept ブロック内で return 文が実行されたとしても、関数の終了前に必ず finally ブロックが通過します。そのため、ファイルのクローズ、データベース接続の切断、一時データの削除といった「後始末(クリーンアップ)」の処理に最適です。

実践的なコード例

具体的な例として、外部ファイルからのデータ読み込みをシミュレートする関数を作成します。

  1. try: データ読み込みを試みる(エラーの可能性あり)
  2. except: 読み込みエラーを処理する
  3. else: 読み込んだデータを加工・表示する(エラーがなければ実行)
  4. finally: 接続切断処理を行う(必ず実行)
def process_file_data(filename):
    print(f"--- '{filename}' の処理を開始 ---")
    
    # 模擬的なデータストア
    dummy_files = {
        "data.txt": [10, 20, 30],
        "empty.txt": []
    }

    try:
        # 1. データ読み込み(危険な処理)
        if filename not in dummy_files:
            raise FileNotFoundError(f"ファイル '{filename}' が見つかりません。")
        
        data = dummy_files[filename]
        
        # データを割る処理(空リストだと ZeroDivisionError の可能性)
        average = sum(data) / len(data)

    except FileNotFoundError as e:
        # 2. ファイルがない場合のエラー処理
        print(f"[Error] ファイルエラー: {e}")
    
    except ZeroDivisionError:
        # 2. データが空で計算できない場合のエラー処理
        print("[Error] 計算エラー: データが空のため平均を計算できません。")

    else:
        # 3. 正常終了時の処理
        # ここで新たなエラーが起きても、上記の except には捕捉されない(安全)
        print(f"[Success] 平均値の計算に成功しました: {average:.2f}")

    finally:
        # 4. 終了処理(必ず実行)
        print("[Cleanup] ファイル接続を切断しました。")
        print("--------------------------------\n")

# --- 実行テスト ---

# ケース1: 正常終了
process_file_data("data.txt")

# ケース2: ファイルが存在しないエラー (FileNotFoundError)
process_file_data("unknown.csv")

# ケース3: 計算エラー (ZeroDivisionError)
process_file_data("empty.txt")

実行結果:

--- 'data.txt' の処理を開始 ---
[Success] 平均値の計算に成功しました: 20.00
[Cleanup] ファイル接続を切断しました。
--------------------------------

--- 'unknown.csv' の処理を開始 ---
[Error] ファイルエラー: ファイル 'unknown.csv' が見つかりません。
[Cleanup] ファイル接続を切断しました。
--------------------------------

--- 'empty.txt' の処理を開始 ---
[Error] 計算エラー: データが空のため平均を計算できません。
[Cleanup] ファイル接続を切断しました。
--------------------------------

動作のポイント

  • 成功時 (data.txt): try -> else -> finally の順に実行されました。
  • 失敗時 (unknown.csv, empty.txt): try -> except -> finally の順に実行されました。
  • どのような結果になろうとも、finally ブロックにある [Cleanup] のメッセージは必ず出力されています。

まとめ

  • else: 例外が起きなかったときに実行されます。try ブロックを「例外監視が必要なコード」だけに絞るために使います。
  • finally: 例外の有無にかかわらず、必ず最後に実行されます。リソースの解放など、終了処理を保証するために使います。

これらを使いこなすことで、エラーに強く、リソースリーク(解放漏れ)のない安全なプログラムを記述できます。

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

この記事を書いた人

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

目次