Pythonの例外処理構文(try-except)には、あまり知られていないものの、非常に重要な役割を持つ2つのオプション、else 節と finally 節が存在します。
これらを適切に組み合わせることで、「エラーが起きなかったときだけ実行したい処理」や、「エラーの有無にかかわらず必ず実行したい終了処理(リソースの解放など)」を明確に記述できます。
この記事では、try-except-else-finally の完全な構文と、それぞれのブロックの役割について解説します。
例外処理の完全な構文
例外処理の構文は、最大で4つのブロックで構成されます。
try:
# 例外が発生する可能性のある処理
except 例外クラス:
# 例外が発生した場合の処理
else:
# 例外が発生しなかった場合の処理
finally:
# 例外の有無にかかわらず、最後に必ず実行される処理
else 節:正常終了時の処理
else ブロックは、try ブロック内で例外が発生しなかった場合のみ実行されます。
「それなら try ブロックの最後に書けばいいのでは?」と思われるかもしれませんが、else に分けることには明確なメリットがあります。それは、try ブロックの中身を最小限にできる点です。
try ブロック内には「例外が発生する可能性があるコード」だけを記述し、「その結果を使って行う安全な処理」は else に記述することで、意図しない例外まで except で捕捉してしまうリスクを減らすことができます。
finally 節:終了処理(クリーンアップ)
finally ブロックは、例外が発生してもしなくても、必ず最後に実行されます。
たとえ try や except ブロック内で return 文が実行されたとしても、関数の終了前に必ず finally ブロックが通過します。そのため、ファイルのクローズ、データベース接続の切断、一時データの削除といった「後始末(クリーンアップ)」の処理に最適です。
実践的なコード例
具体的な例として、外部ファイルからのデータ読み込みをシミュレートする関数を作成します。
- try: データ読み込みを試みる(エラーの可能性あり)
- except: 読み込みエラーを処理する
- else: 読み込んだデータを加工・表示する(エラーがなければ実行)
- 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: 例外の有無にかかわらず、必ず最後に実行されます。リソースの解放など、終了処理を保証するために使います。
これらを使いこなすことで、エラーに強く、リソースリーク(解放漏れ)のない安全なプログラムを記述できます。
