閉じる

try-except-elseの使い方: finallyとの違いを解説(Python)

エラー処理では、正常系だけに実行したい処理と、失敗時に実行したい処理、成功失敗に関係なく片付けたい処理を分けることが重要です。

Pythonのtry-except-elseは「例外が起きなかったときだけ」実行されるelseを持ち、読みやすく安全なコードに役立ちます

本記事ではfinallyとの違いも含め、初心者向けに丁寧に解説します。

try-except-elseとは(Python)

エラーが発生しなかった場合のみ実行するelse

elseの位置と意味

try-except-elseにおけるelseは、tryブロックで例外が起きなかった場合にだけ実行」される特別な節です

構造としてはexceptの後、finallyより前に書きます。

これにより、エラーがなかった場合にのみ行いたい「後続の正常処理」を明確に分離できます。

elseを使わない場合との違い

もしelseを使わない場合、成功時の処理をtryの中に書きがちで、「どこまでが例外を想定したい範囲か」が不明瞭になります

例外が出るかもしれない最小限の処理だけをtryに閉じ込め、成功時の本筋処理はelseに分けると読みやすくなります。

try-except-elseの基本構文と実行順序

基本構文

もっともよく使う4つの節はtryexceptelsefinallyです

まずは構文を確認します。

Python
# 基本構文の例
try:
    # 例外が起こるかもしれない最小限の処理を書く
    risky_value = 10 / 2
except ZeroDivisionError as e:
    # 特定の例外が起きたときの処理
    print("ゼロ除算エラー:", e)
else:
    # tryで例外が発生しなかった場合のみ実行される
    print("成功しました。結果:", risky_value)
finally:
    # 成功・失敗に関わらず必ず実行される
    print("片付け処理を実行しました")

実行順序の理解

実行順序は「try → (例外があれば) except → (例外がなければ) else → finally」です。

finallyは常に最後に実行されます。

成功時と失敗時でどの節が動くかが変わる点を押さえましょう。

成功時とエラー時の出力の違い

下の小さなデモで、成功と失敗の両パターンを確認します。

Python
def demo(mode: str) -> None:
    print(f"--- mode={mode} ---")
    try:
        if mode == "ok":
            x = 6 / 2   # 成功(例外なし)
        else:
            x = 6 / 0   # 失敗(ZeroDivisionError)
    except ZeroDivisionError:
        print("except: ゼロ除算でした")
    else:
        print(f"else: 成功。x={x}")
    finally:
        print("finally: 必ず実行されます")

demo("ok")
demo("ng")

実行結果(成功と失敗の2パターン):

実行結果
--- mode=ok ---
else: 成功。x=3.0
finally: 必ず実行されます
--- mode=ng ---
except: ゼロ除算でした
finally: 必ず実行されます

成功時はelseが動き、失敗時はexceptが動き、どちらでもfinallyが動くのがポイントです。

使いどころの考え方(初心者向け)

何をtryに、何をelseに分けるか

tryには「失敗する可能性がある操作(最小限)」、elseには「成功したことを前提に進めたい本筋の処理」を置きます

例えば、ファイルを開く処理はtry、開けたファイルの内容で計算する処理はelseが典型です。

使わない方がよい場面

elseの中で再び例外が多発するような重い処理を書くと理解が難しくなります

elseは短くシンプルに保ち、必要なら別関数に切り出すと読みやすくなります。

try-except-elseの使い方(サンプル)

計算が成功したときだけメッセージを出す

ゼロ除算の可能性がある割り算を例に、成功時だけ結果を表示するサンプルです

Python
def safe_div(a: float, b: float) -> None:
    """a / b を試み、成功時だけ結果を表示する"""
    try:
        result = a / b  # ここで ZeroDivisionError の可能性
    except ZeroDivisionError as e:
        print(f"エラー: ゼロ除算です ({e})")
    else:
        # 例外がなかったので、ここは成功時だけ通る
        print(f"成功: {a} / {b} = {result}")

safe_div(8, 2)   # 成功パターン
safe_div(5, 0)   # エラーパターン
実行結果
成功: 8 / 2 = 4.0
エラー: ゼロ除算です (division by zero)

成功時の表示をelseに移したことで、tryの範囲は「例外が起きそうな最小限」に絞れています

この分離が読みやすさと保守性につながります。

ファイル読み込みが成功したら処理を続ける

ファイルを開く部分だけをtryに入れ、開けたときだけ中身を使って計算を行う例です

デモのためにファイル有無を切り替えられるようにしています。

Python
import os

def read_first_int_and_double(simulate_missing: bool) -> None:
    """ファイルが開けたら先頭行を整数として読み、2倍して表示"""
    filename = "example_numbers.txt"

    # デモ用: ファイルを用意するかどうかを切り替え
    if not simulate_missing:
        with open(filename, "w", encoding="utf-8") as f:
            f.write("42\nhello\n")

    try:
        f = open(filename, "r", encoding="utf-8")  # FileNotFoundError の可能性
    except FileNotFoundError as e:
        print(f"エラー: ファイルがありません ({e})")
    else:
        # ファイルが開けたときだけ続きの処理をする
        with f:
            first_line = f.readline().strip()
            # else の中で起きた別の例外はこの except では捕まらない点に注意
            value = int(first_line)  # ValueError の可能性
            print("2倍の結果:", value * 2)
    finally:
        # デモの片付け(存在すれば削除)
        if os.path.exists(filename):
            os.remove(filename)

print("=== 成功ケース ===")
read_first_int_and_double(simulate_missing=False)

print("=== 失敗ケース(ファイルなし) ===")
read_first_int_and_double(simulate_missing=True)
実行結果
=== 成功ケース ===
2倍の結果: 84
=== 失敗ケース(ファイルなし) ===
エラー: ファイルがありません ([Errno 2] No such file or directory: 'example_numbers.txt')

tryでは「開く」だけ、elseでは「中身を使う」処理に分けると、責務の境界が明確になります

else内で新しく起きた例外(ここではValueError)は、外側のexceptでは捕まりません

必要ならelseの中でも個別にtry-exceptを使います。

成功時の後処理をelseにまとめる

すべての入力が数値に変換できた場合にだけ、平均を計算してログを出す例です

Python
def process_numbers(texts: list[str]) -> None:
    """全要素の変換が成功したときだけ平均を計算して報告"""
    try:
        numbers = [float(t) for t in texts]  # どれか1つでも変換失敗なら ValueError
    except ValueError as e:
        print("変換エラー:", e)
    else:
        # ここは全要素の変換が成功したときだけ通る
        avg = sum(numbers) / len(numbers)
        print("平均値:", avg)
        print("ログ: 正常に処理が完了しました")

print("=== 成功ケース ===")
process_numbers(["1.5", "2", "3.5"])

print("=== 失敗ケース ===")
process_numbers(["1.5", "NaN?", "3.5"])
実行結果
=== 成功ケース ===
平均値: 2.3333333333333335
ログ: 正常に処理が完了しました
=== 失敗ケース ===
変換エラー: could not convert string to float: 'NaN?'

「全部変換できた」という前提が必要な処理(平均計算やログ)はelseに集約すると安全で読みやすくなります

この分離により、例外時の回復処理と成功時の後処理が衝突しません。

finallyとの違いをやさしく解説

elseは成功時の追加処理

一言まとめ

elseは「例外が起きなかったときだけ走る後続処理」を書く場所です

成功前提のロジック、成功ログ、成功メトリクスの集計などに適します。

典型例

ファイルや入力の検証が済んだ後にだけ、分析や整形を行うといった使い方が代表例です

finallyは必ず実行する片付け

一言まとめ

finallyは「成功しても失敗しても必ず実行される片付け処理」を書く場所です

ファイルを閉じる、ロックを解放する、一時ファイルを削除するなどを記述します。

典型例

外部リソース(ファイル、ソケット、データベース接続)の解放はfinallyに置くのが定石です

以下の表に違いをまとめます。

実行される条件主な用途注意点
elsetryで例外が発生しなかったときだけ成功時の後続処理、ログ、メトリクスelse内での新たな例外は外側のexceptでは捕まらない
finally成否に関わらず常にリソース解放、ロック解除、後始末finallyでreturnすると例外が消えることがある

「成功時の追加処理はelse、必ず必要な後始末はfinally」という役割分担を覚えましょう

elseとfinallyを組み合わせる例

ファイルを開く成否で処理を分岐しつつ、必ずクローズする例です

実務ではwith文が推奨ですが、学習のために明示的にclose()しています。

Python
def read_all_text(filename: str) -> None:
    f = None
    try:
        f = open(filename, "r", encoding="utf-8")  # FileNotFoundError の可能性
    except FileNotFoundError:
        print("ファイルが見つかりません")
    else:
        # 開けたときだけ読み込む
        content = f.read()
        print("読み込み成功。文字数:", len(content))
    finally:
        # f が開かれていれば必ず閉じる
        if f is not None:
            f.close()
        print("クリーンアップ完了")

# デモ用にファイルを作ってから呼び出す
with open("hello.txt", "w", encoding="utf-8") as tmp:
    tmp.write("hello world")

read_all_text("hello.txt")
実行結果
読み込み成功。文字数: 11
クリーンアップ完了

elseは成功時の本処理、finallyは片付け、と役割を分担すると予期せぬリソースリークを防げます

よくあるミスと回避策

ミス1: exceptを広く取りすぎる

bare except(例: except:)はキーボード割り込みなども捕まえてしまい危険です。

回避策はexcept Exception as e:か、できれば具体的な例外名で限定します。

Python
# 悪い例
try:
    do_something()
except:
    pass  # すべて握りつぶしてしまう

# 良い例
try:
    do_something()
except ValueError as e:
    handle_value_error(e)

ミス2: tryが広すぎる

多くの行をtryに含めると、どこが失敗の原因か分かりにくくなります

回避策は「本当に失敗しうる最小限の行」をtryに入れ、後続はelse

Python
# 悪い例: 失敗しない計算まで try に入っている
try:
    f = open("data.txt")
    data = f.read()
    result = complex_transform(data)  # ここで失敗しても open 失敗と混同されやすい
    print(result)
except Exception as e:
    print("何かが失敗:", e)

# 良い例: 開くまでを try、処理は else
try:
    f = open("data.txt")
except FileNotFoundError as e:
    print("ファイルなし:", e)
else:
    with f:
        result = complex_transform(f.read())
        print(result)

ミス3: finallyでreturnしてしまう

finally内のreturnは例外を「上書き」して見えなくすることがあります

回避策はfinallyでは片付けのみにし、戻り値はelsetry側で決めます。

Python
# 悪い例
def bad() -> int:
    try:
        1 / 0
    finally:
        return 0  # 例外が消える

# 良い例
def good() -> int:
    try:
        x = 1 / 1
    except ZeroDivisionError:
        return -1
    else:
        return int(x)
    finally:
        cleanup()

ミス4: elseに重い処理を詰め込みすぎる

elseが長大になると読みづらく、例外の発生源も見失います

回避策はelseでは「成功の確認後にすぐ呼びたい関数を1〜2個呼ぶ」程度にとどめ、詳細は関数に切り出すことです。

初心者向けベストプラクティス(Python)

exceptで例外を広く取りすぎない

まずは「何が起こりうるか」を特定し、exceptは可能な限り具体的な例外で絞り込みます

無闇に広い捕捉はバグの潜伏やデバッグの難しさにつながります。

どうしても広く取りたい場合は、except Exception as e:に限定してログを残し、再送出(raise)を検討しましょう。

elseは短くシンプルに書く

elseには「成功が保証された前提での最小限の処理」だけを書き、長くなりそうなら関数に委譲します

これにより、tryの責務(失敗しうる最小単位)と、elseの責務(成功後の本筋)がはっきりします。

リソースの解放はfinallyで行う

ファイル、ソケット、ロックなどはfinallyまたはwith(コンテキストマネージャ)で必ず解放します

例外が発生しても確実に片付けが実行されるため、リソースリークを防げます。

with open(...)は背後でtry-finally相当の制御をしてくれる便利な構文です。

まとめ

try-except-elseelseは「例外が起きなかったときだけ実行したい処理」を整理する強力な手段です

成功と失敗の流れを明確に分離でき、コードの見通しが良くなります。

成功時の本処理はelse、失敗時の補足はexcept、片付けはfinallyという役割分担を意識してください。

最後にもう一度強調します。

tryは「失敗しうる最小限」、elseは「成功後の本筋」、finallyは「必ずやる片付け」です。

この型を身につければ、エラーに強く読みやすいPythonコードが書けるようになります。

この記事を書いた人
エーテリア編集部
エーテリア編集部

人気のPythonを初めて学ぶ方向けに、文法の基本から小さな自動化まで、実際に手を動かして理解できる記事を書いています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!