代表的な組み込み例外
Pythonには、プログラム実行中に発生しうる様々なエラー状態に対応するための組み込み例外クラスが用意されています。これらを正しく理解することで、デバッグやエラーハンドリングが容易になります。
# リストのインデックスが範囲外の場合
IndexError: list index out of range
# 0による除算を行った場合
ZeroDivisionError: division by zero
# 異なるデータ型間で不適切な演算を行った場合
TypeError: unsupported operand type(s) for +: 'int' and 'str'
# オブジェクトに存在しない属性やメソッドを参照した場合
AttributeError: 'module' object has no attribute 'non_existent_method'
# 指定したファイルが見つからない場合
FileNotFoundError: [Errno 2] No such file or directory: 'data.txt'
# 辞書に存在しないキーを参照した場合
KeyError: 'invalid_key'
try-except構文の基本
Pythonにおける例外処理の基本はtryブロックとexceptブロックで構成されます。try節には例外が発生する可能性のあるコードを記述し、except節にはその例外が発生した際の処理を記述します。
基本的な構造
あらゆる例外をキャッチする基本的な記述方法は以下の通りです。
try:
# 例外が発生する可能性のある処理
result = 10 / 0
except:
# 例外発生時の処理
print("エラーが発生しました")
特定の例外の捕捉
例外の種類を特定して処理を行うには、exceptの後に例外クラス名を指定します。
try:
file = open('nonexistent.txt', 'r')
except FileNotFoundError:
print("ファイルが見つかりません")
複数の例外をまとめて処理
複数の異なる例外に対して同じ処理を行いたい場合は、タプルを使って例外クラスをグループ化できます。
try:
data = [1, 2, 3]
idx = int(input("インデックスを入力: "))
print(data[idx])
except (IndexError, ValueError):
print("無効な入力またはインデックス範囲外のエラーです")
複数のexceptブロックによる分岐
例外の種類ごとに異なる対応を必要とする場合は、exceptブロックを並べて記述します。これはif-elif文のような挙動を示します。
try:
numerator = 100
denominator = int(input("分母を入力: "))
print(numerator / denominator)
except ZeroDivisionError:
print("0で割ることはできません")
except ValueError:
print("数値を入力してください")
例外オブジェクトの取得
asキーワードを使用すると、発生した例外オブジェクトそのものを変数に代入し、エラーメッセージなどの詳細情報を取得できます。
try:
import nonexistent_module
except ImportError as e:
print(f"インポートエラーの詳細: {e}")
elseとfinallyブロック
例外処理のフローをより細かく制御するために、elseとfinallyを使用できます。
- else:
tryブロック内で例外が発生しなかった場合にのみ実行されます。 - finally: 例外の発生有無にかかわらず、必ず最後に実行されます。主にファイルのクローズやリソースの解放に使用されます。
try:
file = open('sample.txt', 'r')
content = file.read()
except FileNotFoundError:
print("ファイルが存在しません")
else:
print(f"読み込み成功: {len(content)}文字")
finally:
print("処理終了")
# リソースの解放処理など
ネストされた例外処理
tryブロックを入れ子にすることも可能です。内側のexceptで処理されなかった例外は、外側のtry-exceptへと伝播(バブルアップ)していきます。
try:
try:
text = "hello"
number = int(text)
except ValueError:
print("内部ブロック: 値の変換に失敗しました")
except:
print("外部ブロック: 捕捉されなかった例外を処理します")
上記の例では、内側のint(text)がValueErrorを発生させます。これは内側のexcept ValueErrorで捕捉されるため、「内部ブロック」のメッセージが出力されます。もし内側でIndexErrorを捕捉しようとしていた場合、例外は外側へ伝播し、「外部ブロック」が実行されます。
例外の明示的な発生 (raise)
プログラマの意図的に例外を発生させるにはraiseキーワードを使用します。これにはいくつかの使用方法があります。
現在の例外の再スロー
exceptブロック内でraiseのみを記述すると、捕捉した例外を再度呼び出し元へスローします。
try:
# 何らかの処理
pass
except Exception:
# ロギングなどの処理を行った後、再度例外を発生させる
raise
新しい例外の発生
特定の例外クラスを指定してスローします。
raise TypeError("型が一致しません")
バリデーションへの応用
raiseは入力値の検証など、ロジック上エラーとみなすべき状況で活用されます。以下は、年齢が正の整数であるかをチェックする例です。
def validate_age(age_str):
try:
age = int(age_str)
except ValueError:
raise ValueError("年齢は整数で入力してください")
if age < 0:
raise ValueError("年齢は0以上である必要があります")
return age
try:
user_input = input("年齢を入力: ")
valid_age = validate_age(user_input)
print(f"年齢 {valid_age} が登録されました")
except ValueError as err:
print(f"入力エラー: {err}")