Python例外処理:try-exceptで複数のエラーを個別に捕捉する方法と記述順序

プログラムにおいて、一つの処理ブロック内で発生しうるエラー(例外)の種類は一つとは限りません。例えば、データの読み込み処理では「ファイルが見つからない」「データ形式が不正」「必要な値が欠けている」など、様々な問題が発生する可能性があります。

Pythonの try-except 文では、複数の except ブロックを記述することで、エラーの種類に応じた適切な対処(エラーハンドリング)を個別に実装できます。

この記事では、複数の例外を捕捉するための構文と、記述する際の重要なルールについて解説します。

目次

複数の例外を捕捉する基本構文

try ブロックの後に、捕捉したい例外の数だけ except ブロックを列挙します。

構文:

try:
    # エラーが発生する可能性のある処理
except 例外A:
    # 例外Aが発生した場合の処理
except 例外B:
    # 例外Bが発生した場合の処理
except Exception:
    # 上記以外の全ての例外が発生した場合の処理

プログラムは上から順に except 節を評価し、発生した例外と一致(または継承関係にある)型を見つけた時点で、そのブロックを実行します。実行される except ブロックは一つだけです。

サンプルコード:サーバー設定の検証

具体的な例として、サーバーの設定情報(辞書データ)を読み込み、1プロセスあたりのメモリ割り当て量を計算する関数を作成します。この処理では、以下のエラーが想定されます。

  1. 設定項目(キー)が存在しない (KeyError)
  2. プロセス数が0で、割り算ができない (ZeroDivisionError)
  3. 設定値が数値ではない (TypeError)
def calculate_memory_per_process(server_config):
    print("--- 設定の検証と計算を開始 ---")
    
    try:
        # 辞書から値を取得(キーがないと KeyError)
        total_mem = server_config["total_memory_gb"]
        proc_count = server_config["process_count"]
        
        # 割り算を実行(proc_countが0だと ZeroDivisionError)
        # 値が文字列などの場合、割り算で TypeError
        memory_allocation = total_mem / proc_count
        
        print(f"成功: 1プロセスあたり {memory_allocation:.2f} GB を割り当てます。")

    except KeyError as e:
        print(f"設定エラー: 必要なキー {e} が見つかりません。")

    except ZeroDivisionError:
        print("数値エラー: プロセス数に 0 は指定できません。")

    except TypeError:
        print("型エラー: メモリ容量とプロセス数は数値で指定してください。")

    except Exception as e:
        # 想定外のエラーをキャッチする
        print(f"予期せぬエラーが発生しました: {e}")

    print("--- 処理終了 ---\n")

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

# 1. 正常なデータ
valid_data = {"total_memory_gb": 32, "process_count": 4}
calculate_memory_per_process(valid_data)

# 2. キー不足 (KeyError)
missing_key_data = {"total_memory_gb": 32}
calculate_memory_per_process(missing_key_data)

# 3. ゼロ除算 (ZeroDivisionError)
zero_proc_data = {"total_memory_gb": 32, "process_count": 0}
calculate_memory_per_process(zero_proc_data)

# 4. 型不正 (TypeError)
invalid_type_data = {"total_memory_gb": "32GB", "process_count": 4}
calculate_memory_per_process(invalid_type_data)

実行結果:

--- 設定の検証と計算を開始 ---
成功: 1プロセスあたり 8.00 GB を割り当てます。
--- 処理終了 ---

--- 設定の検証と計算を開始 ---
設定エラー: 必要なキー 'process_count' が見つかりません。
--- 処理終了 ---

--- 設定の検証と計算を開始 ---
数値エラー: プロセス数に 0 は指定できません。
--- 処理終了 ---

--- 設定の検証と計算を開始 ---
型エラー: メモリ容量とプロセス数は数値で指定してください。
--- 処理終了 ---

このように、発生したエラーの種類に応じて、適切なエラーメッセージを表示し分けることができます。

例外の記述順序と親クラス

複数の except を記述する際、例外クラスの継承関係に注意が必要です。

Pythonの例外はクラス階層を持っており、Exception はほぼすべての例外の親クラスです。そのため、except Exception: を最初に書いてしまうと、すべてのエラーがそこで捕捉されてしまい、後続の個別の except ブロック(KeyError など)に到達しなくなります。

悪い例:

try:
    # 処理
except Exception:
    # 全てここで止まってしまう
    print("エラー")
except KeyError:
    # ここには絶対に到達しない(到達不能コード)
    print("キーエラー")

ルール: 具体的で細かい例外(子クラス)を先に記述し、包括的な例外(親クラス、Exceptionなど)は最後に記述します。

複数の例外をまとめて処理する

異なる種類の例外に対して、まったく同じ処理を行いたい場合は、例外クラスをタプルとしてまとめて指定できます。

    except (ValueError, TypeError) as e:
        print(f"値または型に問題があります: {e}")

これにより、コードの重複を防ぎ、簡潔に記述できます。

まとめ

  • try-except 構文では、except ブロックを複数記述して、エラーの種類ごとに処理を分岐できます。
  • KeyErrorZeroDivisionError など、想定される具体的なエラーを個別にハンドリングすることで、堅牢なプログラムになります。
  • except の順序は重要です。具体的な例外を先に、Exception のような包括的な例外は最後に記述します。
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

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

目次