結論から言うと、finally は「成功しても失敗しても、最後に必ず実行したい処理」を書く場所です。

Pythonでは、ファイルを開いたあとに閉じる、処理開始時に作った一時状態を戻す、ログを残すといった後片付けが必要になることがあります。
そのような処理は、途中でエラーが起きても実行したい場合があります。
この記事では、finally の基本と使いどころを、動くコードと一緒に整理します。

この記事でわかること

  • finally が実行されるタイミング
  • tryexceptfinally の基本的な流れ
  • 実務で finally を使う場面と注意点

完成コード

完成コードは次の通りです。

from pathlib import Path


def process_report(path: Path) -> None:
    print("処理を開始します")

    try:
        text = path.read_text(encoding="utf-8")
        if not text.strip():
            raise ValueError("レポートが空です")

        line_count = len(text.splitlines())
        print(f"行数: {line_count}")
    except FileNotFoundError:
        print(f"ファイルが見つかりません: {path}")
    except ValueError as error:
        print(f"入力内容を確認してください: {error}")
    finally:
        print("処理を終了します")


report_path = Path("sample_report.txt")
report_path.write_text("売上レポート\n1行目\n2行目\n", encoding="utf-8")

process_report(report_path)
process_report(Path("missing_report.txt"))

コードのポイント

このコードでは、レポートファイルを読み込み、行数を表示しています。

  • try には、ファイル読み込みと内容確認の処理を書いています
  • except には、ファイルがない場合や内容が空の場合の処理を書いています
  • finally には、成功しても失敗しても最後に実行したい処理を書いています
  • この例では、どちらの場合でも "処理を終了します" が表示されます

finally は、処理結果に関係なく最後に通る場所だと考えると理解しやすいです。

コードを順番に説明します

主要な処理を分けて説明します。

1. try に通常の処理を書きます

try:
    text = path.read_text(encoding="utf-8")
    if not text.strip():
        raise ValueError("レポートが空です")

    line_count = len(text.splitlines())
    print(f"行数: {line_count}")

try の中には、通常実行したい処理を書きます。
この例では、ファイルを読み込み、空でないか確認し、行数を数えています。

ファイルが存在しなければ FileNotFoundError が発生します。
また、ファイルの中身が空なら、自分で ValueError を発生させています。

raise の詳しい使い方は 4-4 で扱いますが、ここでは「処理できない状態をエラーとして扱っている」と理解できれば十分です。

2. except で失敗時の処理を書きます

except FileNotFoundError:
    print(f"ファイルが見つかりません: {path}")
except ValueError as error:
    print(f"入力内容を確認してください: {error}")

except には、エラーが起きたときの処理を書きます。
この例では、ファイルがない場合と、入力内容に問題がある場合を分けています。

except が実行されるかどうかは、エラーの有無によって変わります。
エラーが起きなければ、except の中は実行されません。

一方で、finally は正常に処理できた場合でも、エラーになった場合でも実行されます。
ここが except との大きな違いです。

3. finally に必ず実行したい処理を書きます

finally:
    print("処理を終了します")

finally の中は、try が成功しても、except でエラーを処理しても、最後に実行されます。
そのため、後片付けや終了ログのような処理を書くのに向いています。

たとえば、処理開始時に一時ファイルを作った場合、最後に削除したいことがあります。
また、外部サービスに接続した場合、最後に接続を閉じたいこともあります。
このような「結果に関係なく実行したい処理」が finally の出番です。

実務で使うときのポイント

実務で finally を使う場面は、後片付けが必要な処理です。

  • 一時ファイルを作成したあとに削除する
  • 処理開始と終了のログを必ず残す
  • 外部リソースへの接続を閉じる
  • フラグや状態を元に戻す

ただし、ファイル操作では with open(...)Path.read_text() のような書き方で十分なことも多いです。
with は、ファイルを閉じる処理を自動で扱ってくれるため、単純なファイル読み書きでは finally を自分で書かなくて済みます。

finally は便利ですが、何でも入れる場所ではありません。
通常の処理は try、エラー時の処理は except、必ず行う後片付けは finally と役割を分けると読みやすくなります。

第4章の流れでは、tryexcept で失敗時の動きを決め、finally で後片付けを整理します。
次の 4-4 では、自分でエラーを出す raise を学ぶと、処理できない状態をより明確に表せるようになります。

よくある勘違い・注意点

  • finally はエラーが起きたときだけ実行されるわけではありません。正常終了でも実行されます
  • エラー時の説明や代替処理は、基本的に except に書きます
  • 後片付けが不要な短い処理では、無理に finally を使わなくてもよいです
  • ファイルを閉じる目的だけなら、まず with を使えないか考えると読みやすくなります

まとめ

  • finally は、成功しても失敗しても最後に実行される処理です
  • 後片付け、終了ログ、状態の復元などに向いています
  • エラー時の処理は except、必ず行う処理は finally と分けて考えます
  • 単純なファイル操作では、with を使うほうが自然な場合もあります

次の記事