はじめに
前回はtry
, except
, finally
を使った基本的な例外処理を学びましたね。プログラムを書いていると、予期せぬエラー(例外)が発生することがあります。今回は、Pythonに用意されている様々な組み込み例外の種類と、自分で独自の例外を定義するカスタム例外について学びましょう!
例外の種類を理解することで、エラーの原因を特定しやすくなり、より的確なエラーハンドリングが可能になります。
Pythonの組み込み例外
Pythonには、様々な種類のエラーに対応する多くの組み込み例外クラスが用意されています。すべてを覚える必要はありませんが、よく遭遇する代表的なものを知っておくとデバッグが格段にしやすくなります。
代表的な組み込み例外
以下によく使われる組み込み例外の例をいくつか紹介します。
例外クラス | 説明 | 発生する例 |
---|---|---|
SyntaxError | Pythonの文法が間違っている場合に発生します。プログラム実行前に検出されます。 |
|
NameError | 定義されていない変数や関数を使用しようとした場合に発生します。 |
|
TypeError | 異なるデータ型のオブジェクト間で不適切な操作を行おうとした場合に発生します。 |
|
ValueError | データ型は正しいものの、値が不適切な場合に発生します。 |
|
IndexError | リストやタプルなどで、存在しないインデックス番号を指定した場合に発生します。 |
|
KeyError | 辞書で、存在しないキーを指定した場合に発生します。 |
|
ZeroDivisionError | 数値をゼロで割ろうとした場合に発生します。 |
|
FileNotFoundError | 存在しないファイルを開こうとした場合に発生します。 |
|
ImportError / ModuleNotFoundError | 存在しないモジュールをインポートしようとした場合に発生します。(ModuleNotFoundError は ImportError のサブクラスです) |
|
これら以外にも多くの組み込み例外があります。完全なリストはPythonの公式ドキュメントで確認できます。
except
節では、特定の例外クラスを指定することで、その種類のエラーだけを捕捉できます。複数の例外をまとめて捕捉したり、より広い範囲の例外(例えばException
)を捕捉することも可能です。 例外の階層構造
Pythonの例外はクラスとして定義されており、他のクラスと同様に継承関係を持っています。全ての組み込み例外はBaseException
クラスを頂点とする階層構造になっています。
私たちが通常扱う例外(SystemExit
やKeyboardInterrupt
などを除く)のほとんどは、Exception
クラスを継承しています。この階層構造を理解しておくと、except
節でどのレベルの例外を捕捉するかを考える際に役立ちます。
例えば、ZeroDivisionError
はArithmeticError
のサブクラス(子クラス)であり、ArithmeticError
はException
のサブクラスです。したがって、except ArithmeticError:
と書くと、ZeroDivisionError
だけでなく、OverflowError
やFloatingPointError
といった他の算術エラーも捕捉できます。
try: result = 10 / 0
except ArithmeticError as e: print(f"算術エラーが発生しました: {e}") # ZeroDivisionErrorもここで捕捉される
except Exception:
のように、あまりにも広い範囲の例外を捕捉すると、予期しないエラーまで捕捉してしまい、問題の原因特定が難しくなることがあります。可能な限り、具体的な例外クラスを指定するように心がけましょう。 カスタム例外の作成
組み込み例外だけでは表現しきれない、アプリケーション固有のエラー状況を扱いたい場合があります。そんなときは、自分でカスタム例外を定義することができます。
カスタム例外を作成するには、Exception
クラス(またはそのサブクラス)を継承した新しいクラスを定義します。
カスタム例外の定義例
例えば、アプリケーションで「残高不足」という独自のエラーを定義したい場合、次のように書けます。
# 独自例外クラスを定義 (Exceptionを継承)
class InsufficientBalanceError(Exception): """残高不足を表すカスタム例外""" def __init__(self, balance, amount): self.balance = balance self.amount = amount # 親クラス(Exception)のコンストラクタを呼び出し、エラーメッセージを設定 super().__init__(f"残高不足です。残高: {balance}, 引き出し額: {amount}")
# 例: このカスタム例外を使用する関数
def withdraw(balance, amount): if amount > balance: # 残高不足の場合、カスタム例外を発生させる raise InsufficientBalanceError(balance, amount) else: print(f"{amount}円引き出しました。新しい残高: {balance - amount}") return balance - amount
# カスタム例外を捕捉する例
my_balance = 1000
try: withdraw(my_balance, 1500)
except InsufficientBalanceError as e: print(f"エラーが発生しました: {e}") # e.balance や e.amount のように、カスタム例外に追加した属性にアクセスできる print(f"現在の残高: {e.balance}")
except Exception as e: print(f"予期せぬエラーが発生しました: {e}")
カスタム例外を使うメリット
- コードの可読性向上: エラーの種類が明確になり、何が問題なのか理解しやすくなります。
- より詳細なエラーハンドリング: アプリケーション固有の状況に応じた、きめ細やかなエラー処理が可能になります。
- エラー情報の追加: 例外クラスに独自の属性(上の例では
balance
とamount
)を持たせることで、エラー発生時の状況に関する追加情報を渡すことができます。
大規模なプログラムやライブラリを開発する際には、カスタム例外を適切に定義することが、コードの保守性や堅牢性を高める上で非常に重要になります。
まとめ
今回は、Pythonの様々な組み込み例外の種類と、独自のカスタム例外を作成する方法について学びました。
- 組み込み例外:
TypeError
,ValueError
,IndexError
など、よく発生するエラーの種類を理解することが重要です。 - 例外の階層: 例外クラスは継承関係を持っており、
except
節で捕捉する範囲を意識することが大切です。 - カスタム例外:
Exception
クラスを継承して独自の例外を定義することで、アプリケーション固有のエラーを分かりやすく扱えます。
例外処理は、エラーに強いプログラムを作成するための基本です。様々な例外の種類を知り、適切にハンドリングできるようになりましょう! 次回は、プログラムのバグを見つけて修正するための「デバッグ」について学んでいきます。お楽しみに!
参考情報
- Python 公式ドキュメント – 組み込み例外
Pythonに標準で組み込まれている例外クラスの一覧と階層構造が記載されています。
- Python 公式ドキュメント チュートリアル – エラーと例外
例外処理の基本的な使い方から、カスタム例外の定義方法まで解説されています。