Pythonで実行時に発生するエラーは、try-except文を使うことによって捕捉できます。しかし、エラーが発生したことはわかっても、具体的にどのようなエラーが起きたのかを把握できなければ、適切な対処は困難です。
try-except文ではexcept Exception as eのように記述することによって、例外オブジェクトを変数に格納できます。例外オブジェクトとは、エラー発生時にPythonが自動的に生成するオブジェクトのことで、エラーメッセージや型名などの詳細情報を保持しています。
この記事では、try-exceptでエラー内容を取得する具体的な方法を、実践的なサンプルコードとともに解説していきます。
目次
- Pythonのtry-exceptでエラー内容を取得する方法
- str(e)でエラーメッセージを文字列として取得する
- repr(e)でエラーの型名と引数を含む表現を取得する
- type(e).__name__でエラーの型名だけを取得する
- tracebackモジュールでエラーの発生箇所を特定する方法
- traceback.format_exc()でトレースバック全体を文字列として取得する
- traceback.print_exc()でトレースバックを標準エラー出力に表示する
- 複数の例外を個別に捕捉してエラー内容を取得する方法
- 例外の型ごとにexcept節を分けて処理する
- 1つのexcept節で複数の例外型をまとめて捕捉する
- Pythonのtry-exceptに関するよくある質問
- except Exceptionとexceptだけの違いは何ですか?
- エラー内容をファイルに書き出す方法はありますか?
Pythonのtry-exceptでエラー内容を取得する方法
try-except文でエラー内容を取得するには、except節にasキーワードを使って例外オブジェクトを変数に代入します。基本的な構文は、以下の通りです。
try:
# エラーが発生する可能性のある処理
except 例外型 as 変数名:
# エラー内容を使った処理
代入された例外オブジェクトはargs属性にコンストラクタへ渡された引数を保持しています。この例外オブジェクトをstr()やrepr()、type()などと組み合わせることで、用途に応じたエラー情報を取り出せます。
The except clause may specify a variable after the exception name. The variable is bound to the exception instance which typically has an args attribute that stores the arguments.
出典:Python公式ドキュメント - Errors and Exceptions
ここでは代表的な3つの取り出し方として、str(e)、repr(e)、type(e).__name__の使い分けを見ていきます。
str(e)でエラーメッセージを文字列として取得する
str(e)は、例外オブジェクトを文字列に変換して、エラーの概要を取得する方法です。ユーザーへのエラー通知やログ出力など、エラーの内容を簡潔に確認したい場面で使用します。
try:
number = int("abc")
except ValueError as e:
print(str(e))
上記のコードでは、文字列"abc"を整数に変換しようとしてValueErrorが発生します。str(e)を使うことによって、invalid literal for int() with base 10: 'abc'というエラーメッセージが出力されます。
str(e)が返す文字列は、例外オブジェクトの__str__()メソッドの実装に依存しており、通常はコンストラクタに渡された引数(args)の内容をもとに生成されます。組み込み例外のほとんどは人間が読みやすいメッセージを返すため、簡易的なエラー通知に適しています。
ただし、例外の型名は含まれないため、どの種類のエラーが発生したかも併せて確認したい場合には不向きです。型名を含めて出力したい場合は、次に紹介するrepr(e)やtype(e).__name__を使用してください。
repr(e)でエラーの型名と引数を含む表現を取得する
repr(e)は、例外オブジェクトの「公式な文字列表現」を返す方法です。多くの組み込み例外ではクラス名(引数)という形式で出力されるため、例外の型名と内容をまとめて1行で確認したい場面で使用します。
try:
result = 10 / 0
except ZeroDivisionError as e:
print(repr(e))
上記のコードを実行すると、ZeroDivisionError('division by zero')と出力されます。str(e)とは異なり、先頭にZeroDivisionErrorという例外クラス名が付与されるため、エラーの種類をひと目で確認できます。
repr(e)が返す内容は、BaseExceptionの__repr__()の実装に基づくもので、厳密には「型名 + コンストラクタに渡された引数(args)の表現」です。ただし、Pythonの標準的な例外では引数にエラーメッセージが渡されるため、結果として型名とメッセージを同時に確認できる表現になり、ログに1行で記録しておきたい用途に便利です。
type(e).__name__でエラーの型名だけを取得する
type(e).__name__は、例外オブジェクトの型名(クラス名)だけを文字列として取得する方法です。ログにエラー型名をフォーマットに合わせて記録したい場合や、エラー型名と本文を別々に扱いたい場面で使用します。
try:
data = {"key": "value"}
print(data["nonexistent"])
except KeyError as e:
error_type = type(e).__name__
error_message = str(e)
print(f"エラー型: {error_type}")
print(f"エラー内容: {error_message}")
上記のコードでは、辞書に存在しないキーを参照してKeyErrorが発生します。type(e).__name__でKeyErrorという型名を取得し、str(e)でエラーメッセージを取得することによって、出力のフォーマットを自由に制御できます。
なお、エラーの種類に応じて処理を分岐させたい場合、type(e).__name__で取得した文字列を比較する方法は推奨されません。タイプミスによるバグの原因になるうえ、継承関係が考慮されないためです。
例外処理の分岐は、後述する複数のexcept節を型ごとに書く方法を第一選択肢としてください。すでに捕捉済みの例外をさらに細かく分類したい特殊なケースに限って、isinstance(e, SomeError)による型チェックを補助的に使う場面があります。
tracebackモジュールでエラーの発生箇所を特定する方法
tracebackモジュールとは、Pythonの標準ライブラリに含まれるモジュールで、例外発生時のスタックトレース(関数の呼び出し履歴)を取得・表示する機能を提供します。str(e)やrepr(e)ではエラーメッセージや型名は取得できますが、エラーがコードのどの行で発生したかまでは確認できません。
tracebackモジュールを使うことによって、エラーの発生箇所をファイル名・行番号・関数名とともに特定できます。ここでは、出力先が異なる2つの関数traceback.format_exc()とtraceback.print_exc()の使い分けを解説します。
いずれも「現在処理中の例外」に対して動作する関数のため、except節の中で呼び出すのが基本です。except節の外で呼び出すと、直前の例外情報に依存したり、意図した結果が得られなかったりする可能性があります。
traceback.format_exc()でトレースバック全体を文字列として取得する
traceback.format_exc()は、現在処理中の例外のトレースバック情報を文字列として返す関数です。戻り値が文字列であるため、変数に格納してログファイルへの書き出しやメール通知など、さまざまな用途に活用できます。
import traceback
def divide(a, b):
return a / b
try:
result = divide(10, 0)
except ZeroDivisionError:
error_detail = traceback.format_exc()
print(error_detail)
上記のコードを実行すると、以下のようなトレースバック情報が出力されます。ファイル名・行番号・関数名・エラーメッセージが含まれるため、エラーの発生箇所を正確に特定できます。
Traceback (most recent call last):
File "example.py", line 6, in <module>
result = divide(10, 0)
File "example.py", line 4, in divide
return a / b
ZeroDivisionError: division by zero
traceback.format_exc(limit=None, chain=True) - Format the exception information and stack trace entries from the current exception, as a string.
出典:Python公式ドキュメント - traceback — Print or retrieve a stack traceback
str(e)だけでは発生箇所がわからないエラーも、format_exc()なら原因の特定が容易です。本番環境でエラー内容を保存したい場合は、単純なopen()による書き出しよりも、後述のloggingモジュールを使う方が一般的です。
traceback.print_exc()でトレースバックを標準エラー出力に表示する
traceback.print_exc()は、現在処理中の例外のトレースバック情報を、既定で標準エラー出力(sys.stderr)に直接表示する関数です。format_exc()が文字列を返すのに対して、print_exc()は表示まで自動的に行うため、デバッグ中にすぐ結果を確認したい場面で使用します。
import traceback
try:
numbers = [1, 2, 3]
print(numbers[10])
except IndexError:
print("エラーが発生しました。詳細は以下の通りです。")
traceback.print_exc()
上記のコードでは、リストの範囲外のインデックスにアクセスしてIndexErrorが発生します。traceback.print_exc()を呼び出すことによって、トレースバック情報がそのまま標準エラー出力に表示されます。
print()による出力は通常sys.stdoutに送られるのに対し、print_exc()は既定でsys.stderrに出力される点に注意してください。なお、キーワード引数fileにファイルオブジェクトを指定することで、出力先を変更することも可能です。
ただし、実務でのログ記録には、後述するloggingモジュールを使う方法が一般的です。
複数の例外を個別に捕捉してエラー内容を取得する方法
実際のプログラムでは、1つのtryブロック内で複数の種類のエラーが発生する可能性があります。エラーの種類ごとに異なるメッセージを表示したり、処理を分岐させたりしたい場合は、複数のexcept節を使って個別に捕捉します。
方法は大きく分けて、型ごとにexcept節を分ける方法と、1つのexcept節にタプルで複数の例外型を指定する方法の2つです。ここから、それぞれの書き方と使い分けのポイントを解説します。
例外の型ごとにexcept節を分けて処理する
except節を複数記述することによって、例外の型ごとに異なる処理を実行できます。エラーの種類に応じてユーザーへのメッセージを変えたい場合や、リカバリ処理を分岐させたい場合に使用します。
def process_data(value, index):
try:
numbers = [10, 20, 30]
result = numbers[index] / value
return result
except ZeroDivisionError as e:
print(f"ゼロ除算エラー: {str(e)}")
return None
except IndexError as e:
print(f"インデックスエラー: {str(e)}")
return None
except Exception as e:
print(f"予期しないエラー: {repr(e)}")
return None
print(process_data(0, 1))
print(process_data(2, 5))
上記のコードでは、ZeroDivisionErrorとIndexErrorをそれぞれ個別のexcept節で捕捉しています。最後のexcept Exception as eは、想定外の通常エラーを広く捕捉するためのフォールバックとして機能します。
ただし、KeyboardInterrupt(Ctrl+Cによる中断)やSystemExit(プログラムの終了要求)などはBaseExceptionの直下に位置し、Exceptionのサブクラスではないため、この書き方では捕捉されません。この点はexcept Exceptionの仕様として押さえておきましょう。
except節は上から順に評価されるため、具体的な例外型を先に記述し、汎用的なExceptionは最後に配置してください。順序を逆にすると、具体的な例外型のexcept節に到達する前にExceptionで捕捉されてしまい、個別の処理が実行されません。
1つのexcept節で複数の例外型をまとめて捕捉する
複数の例外型に対して同じ処理を行いたい場合は、except節にタプルで例外型を指定することによって、1つのexcept節でまとめて捕捉できます。エラーの種類に関わらず共通のエラーハンドリングを行う場面で使用します。
def read_config(filepath, key):
try:
with open(filepath, "r") as f:
config = {}
for line in f:
k, v = line.strip().split("=")
config[k] = v
return config[key]
except (FileNotFoundError, KeyError, ValueError) as e:
error_type = type(e).__name__
print(f"設定読み込みエラー [{error_type}]: {str(e)}")
return None
result = read_config("config.txt", "database_host")
print(result)
上記のコードでは、FileNotFoundErrorやKeyError、ValueErrorの3種類の例外を1つのexcept節でまとめて捕捉しています。type(e).__name__を使うことによって、実際に発生した例外の型名をエラーメッセージに含めています。
タプルで指定する方法は、コードの重複を減らしてメンテナンス性を向上させる効果があります。ただし、例外の種類ごとに異なるリカバリ処理が必要な場合は、前述のようにexcept節を分けて記述してください。
Pythonのtry-exceptに関するよくある質問
except Exceptionとexceptだけの違いは何ですか?
except ExceptionはExceptionクラスとそのサブクラスのみを捕捉するのに対し、exceptだけの記述(bare except)はBaseExceptionを含むすべての例外を捕捉します。bare exceptはKeyboardInterrupt(Ctrl+Cによる中断)やSystemExit(プログラムの終了要求)まで捕捉してしまうため、PEP 8でも使用を避けるべきとされています。
広めに捕捉したい場合はexcept Exceptionを使い、原則としては想定される具体的な例外型を指定するのが推奨されるスタイルです。
エラー内容をファイルに書き出す方法はありますか?
本番環境でのエラー記録には、Pythonの標準ライブラリであるloggingモジュールのlogging.exception()メソッドを使うのが一般的です。あらかじめlogging.basicConfig()などでファイル出力先をハンドラとして設定したうえで、except節の中でこのメソッドを呼び出すことによって、タイムスタンプ付きでエラーメッセージとトレースバックをログファイルへ記録できます。
設定を行わない場合は既定のハンドラによって標準エラー出力に表示されるだけで、ファイルには書き出されない点に注意してください。簡易的に対応したい場合は、traceback.format_exc()で取得したトレースバック文字列をopen()関数でファイルへ書き出す方法もあります。
※上記コンテンツの内容やソースコードはAIで確認・デバッグしておりますが、間違いやエラー、脆弱性などがある場合は、コメントよりご報告いただけますと幸いです。
ITやプログラミングに関するコラム
PythonをWebで実行する方法
共通テスト「情報Ⅰ」2年目で変わる、日本の教育と学び方
gitでブランチ(branch)を切り替える方法
git cloneでブランチを指定する方法
64GBのメモリが必要な人・不要な人の特徴
PCを再起動するコマンド一覧
CapsLock以外で大文字になる原因【Windows編】
パソコンで大文字になるのを解除する方法
面白いAIの活用事例を業界別に紹介
Gitでcommit(コミット)を取り消す方法
ITやプログラミングに関するニュース
サイボウズがkintone AIを正式提供、β版から約1年を経てクレジット制を導入
ロゼッタのラクヤクAIがCSRドラフト作成期間を90%以上短縮、従来4週間を約2日に
AI CROSSが不動産業界向け生成AI伴走支援を開始、アスコットの業務AI実装を実践サポート
日本情報クリエイトが「オーナー提案AIロボⅡ」売買査定を刷新、月1万円からW査定が回数無制限に
Wur株式会社がAI新規事業診断サービス「MVP事業診断レポート」をリリース、12の質問で事業構想を約10分で分析
バトンズがM&A専門家向け「AI概要書」β版を提供開始、企業概要書のドラフトを最速3分で自動生成
SCSKが観光DXサービス「Connexia」を開発、首里城公園でNFT活用の周遊促進が始動
Verdent AI発表、エンジニア不要でソフトウェアを構築する「AIエンジニアリングチーム」が登場
ゼネラルBREXAテクノロジーが外食・小売向けAIサービス「aimana」を開発、店長の意思決定をデータで支援
田中組がKencopa工程AIエージェント製品版を先行利用開始、建設現場の工程管理属人化を解消へ
