はじめに
Pythonで実装している際に、標準のエラーやサードパーティ製ライブラリから出るエラーを独自のカスタムエラーでオーバーライドしてre-raiseする時などがあるかと思いますが、そんな時にエラーチェインする場合としない場合や、そのままraiseするのとraise eとするもので違いがあるのかなど気になったので調べてみました。
今回比較で使用したサンプルコード
try:
with open("sample_file.txt", "r") as file:
content = file.read()
except FileNotFoundError as e:
raise # パターン①: 簡易再送
raise e # パターン②: 元のエラーを再発生
raise RuntimeError("ファイルが見つかりませんでした。") # パターン③: エラー置き換え
raise RuntimeError("ファイルが見つかりませんでした。") from e # パターン④: エラーチェイン付きでエラーを発生
raise RuntimeError("ファイルが見つかりませんでした。") from None # パターン⑤: 元の例外情報を明示的にチェインしないようにエラー置き換え
パターン①: raise
概要: except
ブロック内でraise
を呼び出すと、キャッチされた元の例外をそのまま再発生させます。
Traceback (most recent call last):
File "main.py", line 3, in <module>
with open("sample_file.txt", "r") as file:
FileNotFoundError: [Errno 2] No such file or directory: 'sample_file.txt'
特徴:
- 元の例外を再発生させることで、最初のエラーのコンテキストが維持されるます。
- 最もシンプルな再送方法。
パターン②: raise e
概要: 捕捉したエラーオブジェクトe
を明示的に再発生させます。
Traceback (most recent call last):
File "main.py", line 7, in <module>
raise e
File "main.py", line 3, in <module>
with open("sample_file.txt", "r") as file:
FileNotFoundError: [Errno 2] No such file or directory: 'sample_file.txt'
特徴:
- スタックトレースに
raise e
の行番号が追加され、元のエラー発生箇所に加えて再発生箇所も表示されます。 -
raise
単独のほうが基本的に適切みたい。
パターン③: raise RuntimeError(...)
概要: 元の例外を無視して新しい例外を発生させます。
Traceback (most recent call last):
File "main.py", line 3, in <module>
with open("sample_file.txt", "r") as file:
FileNotFoundError: [Errno 2] No such file or directory: 'sample_file.txt'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "main.py", line 7, in <module>
raise RuntimeError("ファイルが見つかりませんでした。")
RuntimeError: ファイルが見つかりませんでした。
特徴:
- スタックトレースには元のエラーが表示されますが、「何が原因か」の説明がないため、慎重に使用すべき。
パターン④: raise RuntimeError(...) from e
概要: 新しい例外を発生させる際に、元の例外情報をチェイン(原因として関連付け)します。
Traceback (most recent call last):
File "main.py", line 3, in <module>
with open("sample_file.txt", "r") as file:
FileNotFoundError: [Errno 2] No such file or directory: 'sample_file.txt'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "main.py", line 7, in <module>
raise RuntimeError("ファイルが見つかりませんでした。") from e
RuntimeError: ファイルが見つかりませんでした。
特徴:
- 元のエラー情報を保持しつつ、新しい例外を追加します。
- エラーの発生原因を追いやすく、デバッグに有用。
- Pythonicな方法として推奨される。
パターン⑤: raise RuntimeError(...) from None
概要: 新しい例外を発生させる際に、元の例外情報を明示的にチェインしないよう指定します。
Traceback (most recent call last):
File "main.py", line 7, in <module>
raise RuntimeError("ファイルが見つかりませんでした。") from None
RuntimeError: ファイルが見つかりませんでした。
特徴:
- 元のエラー情報(スタックトレース)は完全に省略され、新しい例外のみが表示されます。
- 元のエラー情報を不要として意図的に隠す場合に使用します。
- 原因追跡が難しくなるため、使用には注意が必要です。
最後に
この記事では、Pythonで例外を再送 (re-raise) する方法について、さまざまなパターンまとめてみました。
ご拝読ありがとうございました。