主要な組み込み例外
| 対応: | Python 2(2000) |
|---|
Pythonには多くの組み込み例外クラスが用意されています。エラーの種類を把握しておくと、適切なexceptブロックを書けるようになります。exceptブロックでは具体的な例外クラスを指定し、素のexceptやexcept Exceptionで何でも捕まえることは原則として避けることができます。
主要な組み込み例外
| 例外クラス | 発生する状況 |
|---|---|
| ValueError | 型は正しいが値が不正な場合(例: int('abc'))。 |
| TypeError | 型が不正な操作に使われた場合(例: '文字' + 1)。 |
| KeyError | 辞書に存在しないキーにアクセスした場合。 |
| IndexError | リストの範囲外のインデックスにアクセスした場合。 |
| AttributeError | オブジェクトに存在しない属性やメソッドにアクセスした場合。 |
| FileNotFoundError | 存在しないファイルを開こうとした場合。 |
| ZeroDivisionError | 0で割り算をしようとした場合。 |
| NameError | 未定義の変数を参照した場合。 |
| ImportError | モジュールのインポートに失敗した場合。 |
| StopIteration | イテレータの要素がなくなった場合(通常は自動処理)。 |
| RecursionError | 再帰の深さ上限を超えた場合。 |
| MemoryError | メモリが不足した場合。 |
| OverflowError | 数値演算の結果が大きすぎる場合(floatのみ。intは任意精度)。 |
| NotImplementedError | サブクラスで実装すべきメソッドが未実装の場合に意図的に送出。 |
サンプルコード
builtin_exceptions.py
# ValueError: 値が不正
try:
n = int('abc')
except ValueError as e:
print(f"ValueError: {e}") # invalid literal for int() with base 10: 'abc'
# TypeError: 型が不正
try:
result = '年齢: ' + 25
except TypeError as e:
print(f"TypeError: {e}") # can only concatenate str (not "int") to str
# KeyError: 辞書に存在しないキー
user = {'name': 'user_1', 'age': 28}
try:
email = user['email']
except KeyError as e:
print(f"KeyError: {e}") # KeyError: 'email'
# IndexError: リストの範囲外
members = ['user_1', 'user_2', 'user_3']
try:
print(members[10])
except IndexError as e:
print(f"IndexError: {e}") # list index out of range
# AttributeError: 存在しない属性
try:
'hello'.upper_case() # upper_case()は存在しない
except AttributeError as e:
print(f"AttributeError: {e}")
# FileNotFoundError: ファイルが存在しない
try:
with open('存在しないファイル.txt') as f:
content = f.read()
except FileNotFoundError as e:
print(f"ファイルが見つかりません: {e.filename}")
# ZeroDivisionError: 0除算
try:
result = 100 / 0
except ZeroDivisionError:
print("0で割ることはできません")
# 例外の継承関係を確認
print(issubclass(FileNotFoundError, OSError)) # True
print(issubclass(ZeroDivisionError, ArithmeticError)) # True
print(issubclass(ValueError, Exception)) # True
# 例外オブジェクトの情報
try:
x = int('abc')
except ValueError as e:
print(type(e).__name__) # ValueError
print(str(e)) # エラーメッセージ
print(e.args) # エラー引数のタプル
実行すると次のように出力されます。
python3 builtin_exceptions.py
ValueError: invalid literal for int() with base 10: 'abc'
TypeError: can only concatenate str (not "int") to str
KeyError: 'email'
IndexError: list index out of range
AttributeError: 'str' object has no attribute 'upper_case'
ファイルが見つかりません: 存在しないファイル.txt
0で割ることはできません
True
True
True
ValueError
invalid literal for int() with base 10: 'abc'
("invalid literal for int() with base 10: 'abc'",)
よくあるミス
よくあるミス1: 基底Exceptionクラスをcatchする
すべての例外を一括で捕捉する書き方は、意図しないエラーも隠蔽してしまいます。可能な限り具体的な例外クラスを指定します。
# 基底Exceptionで全例外を捕捉すると原因が分かりにくい
try:
data = {'name': 'user_1', 'power': 9999}
result = data['level'] # KeyError
except Exception:
pass # エラーを飲み込んでしまう
次のように記述します。
# 具体的な例外クラスを指定する
try:
data = {'name': 'user_1', 'power': 9999}
result = data['level']
except KeyError as e:
print(f'キーが見つかりません: {e}')
except TypeError as e:
print(f'型エラー: {e}')
よくあるミス2: except節でraise忘れ
例外を受け取ってログに記録するだけで、上位に伝播させないケースがあります。エラーを飲み込む意図がなければ、『raise』で再送出します。
import logging
# 例外を記録してそのまま終了(上位には伝わらない)
def get_curse_level(name):
try:
levels = {'user_1': 1, 'user_2': 2}
return levels[name]
except KeyError:
logging.error(f'{name} が見つかりません')
# raise がないので None が返ってしまう
次のように記述します。
import logging
# 必要に応じてraiseで再送出する
def get_curse_level_ok(name):
try:
levels = {'user_1': 1, 'user_2': 2}
return levels[name]
except KeyError:
logging.error(f'{name} が見つかりません')
raise # 元の例外を再送出
よくあるミス3: bare exceptの使用
『except:』(例外クラスなし)はKeyboardInterruptやSystemExitも捕捉してしまい、Ctrl+Cでプログラムを止められなくなることがあります。
# bare except はシステム例外も捕捉してしまう
try:
long_process()
except: # KeyboardInterrupt も捕捉する
pass
次のように記述します。
# Exception を明示するか、必要な例外のみ指定する
try:
long_process()
except Exception: # システム例外は捕捉しない
pass
概要
Pythonの例外クラスは階層構造になっています。最上位は『BaseException』で、その下に『Exception』(通常のプログラムエラー)、KeyboardInterrupt、SystemExit などがあります。一般的なエラー処理では『Exception』のサブクラスを扱います。
例外クラスの継承関係を把握することで、適切な粒度でエラーを捕捉できます。例えば『FileNotFoundError』はOSErrorのサブクラスなので、except OSErrorで捕まえることもできますが、より具体的なFileNotFoundErrorを指定する方が意図が明確です。
except節に何も書かずに例外を無視するパターン(pass)は、問題の発見を困難にする場合があります。最低でもログ出力やprint文を入れて、エラーが発生したことを記録します。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。