raise / 独自例外クラス
| 対応: | Python 2(2000) |
|---|
『raise』は意図的に例外を発生させるキーワードです。独自の例外クラスを定義することで、ライブラリや自作モジュール固有のエラーを明確に表現できます。独自例外クラスは必ず『Exception』またはその適切なサブクラスを継承して作ります。『BaseException』を直接継承するのは特殊な用途を除いて避けることができます。
構文
# 例外を発生させる
raise 例外クラス("メッセージ")
# 別の例外を原因として連鎖させる
raise 新しい例外 from 元の例外
# 現在の例外を再送出(exceptブロック内)
raise
# 独自例外クラスの定義
class MyError(Exception):
pass
class MyDetailedError(Exception):
def __init__(self, message, code):
super().__init__(message)
self.code = code
構文・クラス一覧
| 構文・クラス | 概要 |
|---|---|
| raise 例外(msg) | 例外を発生させる。exceptブロック外で使う。 |
| raise | 現在の例外を再送出する。exceptブロック内でのみ使える。 |
| raise 新例外 from 旧例外 | 例外を別の例外に変換しながら、元の原因も保持する。 |
| class MyError(Exception) | Exceptionを継承した独自例外クラスを定義する。 |
| super().__init__(msg) | 親クラスの__init__を呼び出してメッセージを設定する。 |
サンプルコード
raise_basic.py
def divide(a, b):
if b == 0:
raise ZeroDivisionError("ゼロ除算は禁止されています")
return a / b
try:
divide(10, 0)
except ZeroDivisionError as e:
print(e)
実行すると次のように出力されます。
python3 raise_basic.py ゼロ除算は禁止されています
raise_chain.py
def load_config(path):
try:
with open(path) as f:
return f.read()
except FileNotFoundError as e:
raise RuntimeError(f"設定ファイルの読み込みに失敗: {path}") from e
try:
load_config("config.json")
except RuntimeError as e:
print(e)
print(e.__cause__)
実行すると次のように出力されます。
python3 raise_chain.py 設定ファイルの読み込みに失敗: config.json [Errno 2] No such file or directory: 'config.json'
raise_custom_class.py
class HttpError(Exception):
def __init__(self, message, status_code):
super().__init__(message)
self.status_code = status_code
def __str__(self):
return f"[{self.status_code}] {super().__str__()}"
def fetch(url):
if not url.startswith("https://"):
raise HttpError("HTTPSのみ許可されています", 400)
try:
fetch("http://example.com")
except HttpError as e:
print(e)
print(e.status_code)
実行すると次のように出力されます。
python3 raise_custom_class.py [400] HTTPSのみ許可されています 400
よくあるミス
よくあるミス1: BaseExceptionを直接継承する
独自例外クラスを定義するとき、『BaseException』を直接継承すると『except Exception』で捕捉できなくなります。通常は『Exception』を継承します。
class MyError(BaseException):
pass
try:
raise MyError("問題が発生しました")
except Exception as e:
print(e)
次のように記述します。
class MyError(Exception):
pass
try:
raise MyError("問題が発生しました")
except Exception as e:
print(e)
よくあるミス2: raise from を省略して原因を隠す
低レイヤーの例外を高レイヤーの例外に変換するとき、『from』を省略すると元の例外が『__context__』に格納されますが、意図的な変換であることが伝わりにくくなります。『from』を明示すると元の例外がトレースバックに表示されます。
try:
int("abc")
except ValueError:
raise RuntimeError("変換に失敗しました")
次のように記述します。
try:
int("abc")
except ValueError as e:
raise RuntimeError("変換に失敗しました") from e
概要
独自例外クラスを使うことで、エラーの種類をコードで表現できます。例えばWebアプリなら『HttpError』、バリデーション処理なら『ValidationError』といった形でエラーを分類することで、呼び出し側が必要な例外のみを捕捉できます。
『raise 新例外 from 旧例外』は例外チェーンと呼ばれ、低レイヤーの例外を高レイヤーの例外に変換しながら、元の原因を『__cause__』属性として保持します。fromを明示すると元の例外がトレースバックに表示されます。『raise』をfromなしで使った場合はPythonが自動で『__context__』に元の例外を保持しますが、意図的な変換かどうかの区別がつきにくくなります。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。