Python の try 文で例外をキャッチしたときに、エラーメッセージを取得して表示するコード例を書きました。
excep 節の中で『エラー名』や『エラーの内容』を取得して、画面に表示します。
エラーメッセージの取得は、標準の traceback モジュールを使うとできました。
エラーメッセージは、以下のように、狙った範囲だけを取得することができました。
- エラーメッセージ全体 ⇒
traceback.format_exc()
- 最後の行だけ ⇒
traceback.format_exception_only(type(e), e)
- エラー名だけ ⇒
e.__class__.__name__
これらのコード例を紹介します。
取得したエラーは print() 関数で表示しましたが、logging モジュールを使用してログに出力することもできました。
組み込み例外
UnicodeDecodeError や ValueError といった、『組み込み例外』をキャッチした時のエラーメッセージ取得例です。
(Python) 組み込み例外 (UnicodeDecodeError, ValueError など)
『エラーメッセージ全体』を取得
Python マニュアルによると、例外が発生したときに画面にたくさん表示された『エラーメッセージ全体』は、『スタックトレース』と呼ばれるもののようでした。
これらの文字列は、標準の traceback モジュールで取得することができました。
フォーマット エクセ traceback.format_exc() を使用します。
(Python) traceback.format_exc(limit=None, chain=True)
コード例
UnicodeDecodeError が発生した時の『エラーメッセージ全体』を取得しました。
"""『エラーメッセージ全体』を取得"""
import traceback
try:
# SHIFT-JISでエンコードしたものを、わざとUTF-8でデコード。
text = 'あ'.encode('shift-jis').decode('utf-8')
except UnicodeDecodeError:
print('# traceback.format_exc()')
t = traceback.format_exc()
print(t)
実行結果
# traceback.format_exc()
Traceback (most recent call last):
File "c:/*****/main.py", line 6, in <module>
text = 'あ'.encode('shift-jis').decode('utf-8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x82 in position 0: invalid start byte
『最後の行』だけを取得
エラーメッセージの『最後の行』は、フォーマット エクセプション オンリー
traceback.format_exception_only(type(e), e)
で取得することができました。
(Python) traceback.format_exception_only(etype, value)
変数 e
は『except UnicodeDecodeError as e:
』の e
です。
この e
の中身は、例外インスタンスと呼ばれるものでした。
e
は、except 節の中にいる間だけ参照できて、except 節を抜けると参照できなくなる変数でした。
(Python) try
文の説明、except
節の説明、変数 e
が自動的に消去される件とその理由など。
コード例
UnicodeDecodeError が発生した時のエラーメッセージから、『最後の行』だけを取得しました。
ところで、format_exception_only() の戻り値(返り値)はリストでした。
なので、自分は、最初の要素 [0] とか、最後の要素 [-1] を選択して、さらに『末尾の改行 '\n'
』を削除する、といった処理を良くしています。
それから、『最後の行』といっても、リストに要素が2つ以上入っていたケースもありました。
例えば、組み込み関数の eval() に、間違った Python コードを渡したときに見かけました。
(『最後の行』のリストに2つの要素が入っていたエラーの例)
import traceback
try:
eval("'\\U00110000'")
except Exception as e:
t = traceback.format_exception_only(type(e), e)
print(t)
[' File "<string>", line 1\n',
"SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in "
'position 0-9: illegal Unicode character\n']
こういったときに、エラーメッセージをリストのまま使うか、*
でアンパックして使うか、t[0] を使うか、t[-1] を使うか、それとも ''.join(t)
で連結するのがいいのかは、自身の目的に照らして判断する必要がありました。
(Python) 引数リストのアンパック (Unpacking Argument Lists)
以下のコード例では、一例として t[0] を使用しました。
"""『最後の行』だけを取得"""
import traceback
try:
# SHIFT-JISでエンコードしたものを、わざとUTF-8でデコード。
text = 'あ'.encode('shift-jis').decode('utf-8')
except UnicodeDecodeError as e:
# format_exception_only() では『リスト』が返りました 。
t = traceback.format_exception_only(type(e), e)
print('# リストをそのまま表示')
print('# traceback.format_exception_only(type(e), e)')
print(t)
print('\n# リストの中身を選択 & 末尾の改行を削除して表示')
print("# traceback.format_exception_only(type(e), e)[0].rstrip('\\n')")
print(t[0].rstrip('\n'))
実行結果
# リストをそのまま表示
# traceback.format_exception_only(type(e), e)
["UnicodeDecodeError: 'utf-8' codec can't decode byte 0x82 in position 0: invalid start byte\n"]
# リストの中身を選択 & 末尾の改行を削除して表示
# traceback.format_exception_only(type(e), e)[0].rstrip('\n')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x82 in position 0: invalid start byte
『エラー名』だけを取得
UnicodeDecodeError や ValueError といった、『エラー名』の文字列だけを取得するコードです。
特殊属性 を参照して e.__class__.__name__
で取得することができました。
(Python) 組み込み型 – 特殊属性 – instance.__class__
(Python) 組み込み型 – 特殊属性 – definition.__name__
ところで、組み込み関数の class type(object)
の説明にあった通り、e.__class__.__name__
の代わりに type(e).__name__
と書いても、同じ結果を得ることができました。
コード例
Python 組み込み型の特殊属性を参照して、『エラー名』だけを取得しました。
"""『エラー名』だけを取得"""
# モジュールのインポートは不要でした
try:
# SHIFT-JISでエンコードしたものを、わざとUTF-8でデコード。
text = 'あ'.encode('shift-jis').decode('utf-8')
except UnicodeDecodeError as e:
print('# e.__class__.__name__')
t = e.__class__.__name__
print(t)
実行結果
# e.__class__.__name__
UnicodeDecodeError
『エラーメッセージ全体』の『リスト』を取得
例外発生時の『エラーメッセージ全体』は、行ごとの『リスト』として取得することもできました。
sys.exc_info()
の戻り値を traceback.format_exception()
に渡すと取得できました。
(Python) traceback.format_exception(etype, value, tb, limit=None, chain=True)
(Python) 引数リストのアンパック (Unpacking Argument Lists)
コード例
"""『エラーメッセージ全体』の『リスト』を取得"""
import sys # 追加で必要なモジュール
import traceback
import pprint # リストを見やすく改行して print() してくれるモジュール
try:
# SHIFT-JISでエンコードしたものを、わざとUTF-8でデコード。
text = 'あ'.encode('shift-jis').decode('utf-8')
except UnicodeDecodeError:
print('# traceback.format_exception(exc_type, exc_value, exc_traceback)')
(exc_type, exc_value, exc_traceback) = sys.exc_info()
t = traceback.format_exception(exc_type, exc_value, exc_traceback)
pprint.pprint(t, width=120)
print(f'\n# アスタリスク * でアンパックして渡しても OK でした。')
print('# traceback.format_exception(*sys.exc_info())')
t = traceback.format_exception(*sys.exc_info())
pprint.pprint(t, width=120)
(補足です)記号 *
の読みは、スター でも アスタリスク でも アステリスク でも ホシ でもどれでも OK でした。どれも、日本語で言うところの星を指す言葉(または星に由来する言葉)でした。(補足終わり)
実行結果
# traceback.format_exception(exc_type, exc_value, exc_traceback)
['Traceback (most recent call last):\n',
' File "c:/*****/main.py", line 8, in <module>\n'
" text = 'あ'.encode('shift-jis').decode('utf-8')\n",
"UnicodeDecodeError: 'utf-8' codec can't decode byte 0x82 in position 0: invalid start byte\n"]
# アスタリスク * でアンパックして渡しても OK でした。
# traceback.format_exception(*sys.exc_info())
['Traceback (most recent call last):\n',
' File "c:/*****/main.py", line 8, in <module>\n'
" text = 'あ'.encode('shift-jis').decode('utf-8')\n",
"UnicodeDecodeError: 'utf-8' codec can't decode byte 0x82 in position 0: invalid start byte\n"]
例外インスタンス e の属性を取得
『except 例外クラス as e:
』の『e
から参照できる属性たち』を列挙するコード例です。
dir() 関数、sorted() 関数、getattr() 関数を使用して取得しました。
(Python) 組み込み関数 – dir([object])
属性名のリストを取得
(Python) 組み込み関数 – sorted(iterable, *, key=None, reverse=False)
リストをソート
(Python) 組み込み関数 – getattr(object, name[, default])
属性名で値を取得
これで、Visual Studio Code のウォッチ式に表示されるような属性だけを取得して、表示することができました。
また、例外インスタンス e
から取得できる属性は、発生した例外の種類によって変わりました。
(Python) 組み込み例外 – 基底クラス – exception BaseException
– args
, with_traceback(tb)
(Python) 組み込み例外 – 具象例外 – exception UnicodeError
– encoding
, reason
, object
, start
, end
コード例
"""例外インスタンス e の属性を取得するコード例"""
import traceback
try:
# SHIFT-JISでエンコードしたものを、わざとUTF-8でデコード。
text = 'あ'.encode('shift-jis').decode('utf-8')
except UnicodeDecodeError as e:
print('\n# 例外インスタンス e の属性例')
print(f'\ntype(e): {type(e)}')
# Visual Studio Code のウォッチ式に表示
# されるような属性だけを表示してみる。
# dir() 関数、sorted() 関数、getattr() 関数を使用。
for name in sorted(dir(e)):
# アンダースコアで始まる属性をスキップ
if name.startswith('_'):
continue
print(f' e.{name}: {getattr(e, name)}')
else:
print('\n ※ 参照可能な属性は、例外の種類によって変わりました。')
実行結果
# 例外インスタンス e の属性例
type(e): <class 'UnicodeDecodeError'>
e.args: ('utf-8', b'\x82\xa0', 0, 1, 'invalid start byte')
e.encoding: utf-8
e.end: 1
e.object: b'\x82\xa0'
e.reason: invalid start byte
e.start: 0
e.with_traceback: <built-in method with_traceback of UnicodeDecodeError object at 0x000002D0F51AC140>
※ 参照可能な属性は、例外の種類によって変わりました。
例外インスタンス e の属性を取得 – inspect.getmembers() を使用
『例外インスタンス e
の属性たち』は、inspect
モジュールのゲットメンバース inspect.getmembers()
で取得することもできました。
コード例
"""例外インスタンス e の属性を取得するコード例 inspect.getmembers()"""
import traceback
import inspect
try:
# SHIFT-JISでエンコードしたものを、わざとUTF-8でデコード。
text = 'あ'.encode('shift-jis').decode('utf-8')
except UnicodeDecodeError as e:
print('\n# 例外インスタンス e の属性例 - inspect.getmembers()で取得')
print(f'\ntype(e): {type(e)}')
# Visual Studio Code のウォッチ式に表示
# されるような属性だけを表示してみる。
for (name, value) in inspect.getmembers(e):
# アンダースコアで始まる属性をスキップ
if name.startswith('_'):
continue
print(f' e.{name}: {value}')
else:
print('\n ※ 参照可能な属性は、例外の種類によって変わりました。')
実行結果
# 例外インスタンス e の属性例 - inspect.getmembers()で取得
type(e): <class 'UnicodeDecodeError'>
e.args: ('utf-8', b'\x82\xa0', 0, 1, 'invalid start byte')
e.encoding: utf-8
e.end: 1
e.object: b'\x82\xa0'
e.reason: invalid start byte
e.start: 0
e.with_traceback: <built-in method with_traceback of UnicodeDecodeError object at 0x0000026DC0B0AB40>
※ 参照可能な属性は、例外の種類によって変わりました。
自作した例外 (ユーザー定義例外)
『自分で自作した例外 (ユーザー定義例外)』をキャッチした時のエラーメッセージ取得例です。
例外クラスを自作して、そこに渡したエラーメッセージを取得します。
自作例外の作り方は以下の記事に書きました。
⇒ 例外を自作して使うコード例(ユーザー定義例外)
例外は raise 文 で発生させます。
(Python) エラーと例外 – ユーザー定義例外 (User-defined Exceptions)
自作例外のメッセージを取得
やり方は『組み込み例外』のときと同じでした。
コード例
"""自作した例外のエラーメッセージを取得するコード例 (ユーザー定義例外)"""
import traceback
# 自作の例外クラスを定義します。
# 組み込み例外の Exception を継承して、pass と書くだけで OK でした。
class JisakuError(Exception):
"""自作の例外クラス (ユーザー定義例外)"""
pass
# なにか変数を用意する
enc = 'SHIFT-JIS'
print('# レイズ文 (raise 文) で例外を発生させます。')
print("raise JisakuError('エラーメッセージ')")
try:
if enc == 'UTF-8':
pass
else:
raise JisakuError(f"enc='{enc}'を受け取りましたが、UTF-8 が必要です。")
except JisakuError as e:
print('\n# 取得例 (1/3) 『エラーメッセージ全体』を取得')
print('# traceback.format_exc()')
t = traceback.format_exc()
print(t)
print('\n\n# 取得例 (2/3) 『最後の行』だけを取得')
t = traceback.format_exception_only(type(e), e)
print('# traceback.format_exception_only(type(e), e)')
print(t)
print('\n# リストの中身[0]を選択 & 末尾の改行を削除する例')
print("# traceback.format_exception_only(type(e), e)[0].rstrip('\\n')")
print(t[0].rstrip('\n'))
print('\n\n# 取得例 (3/3) 『エラー名』だけを取得')
print('# e.__class__.__name__')
t = e.__class__.__name__
print(t)
print('\n\n# 例外インスタンス e の属性を表示')
print(f'type(e): {type(e)}')
# Visual Studio Code のウォッチ式で表示
# されるような属性だけを表示してみる。
# dir() 関数、sorted() 関数、getattr() 関数を使用。
for name in sorted(dir(e)):
# アンダースコアで始まる属性をスキップ
if name.startswith('_'):
continue
print(f' e.{name}: {getattr(e, name)}')
else:
print('\n (※ e に属性を追加するコード例は、'
'マニュアルの『ユーザー定義例外』に載っていました。)')
実行結果
# レイズ文 (raise 文) で例外を発生させます。
raise JisakuError('エラーメッセージ')
# 取得例 (1/3) 『エラーメッセージ全体』を取得
# traceback.format_exc()
Traceback (most recent call last):
File "c:/*****/main.py", line 22, in <module>
raise JisakuError(f"enc='{enc}'を受け取りましたが、UTF-8 が必要です。")
JisakuError: enc='SHIFT-JIS'を受け取りましたが、UTF-8 が必要です。
# 取得例 (2/3) 『最後の行』だけを取得
# traceback.format_exception_only(type(e), e)
["JisakuError: enc='SHIFT-JIS'を受け取りましたが、UTF-8 が必要です。\n"]
# リストの中身[0]を選択 & 末尾の改行を削除する例
# traceback.format_exception_only(type(e), e)[0].rstrip('\n')
JisakuError: enc='SHIFT-JIS'を受け取りましたが、UTF-8 が必要です。
# 取得例 (3/3) 『エラー名』だけを取得
# e.__class__.__name__
JisakuError
# 例外インスタンス e の属性を表示
type(e): <class '__main__.JisakuError'>
e.args: ("enc='SHIFT-JIS'を受け取りましたが、UTF-8 が必要です。",)
e.with_traceback: <built-in method with_traceback of JisakuError object at 0x0000020B7FBA6280>
(※ e に属性を追加するコード例は、Python マニュアルの『ユーザー定義例外』に載っていました。)
以上です
logging モジュールでロガーを使う方法を書きました。
concurrent.futures
でログを記録するコード例。
multiprocessing
でログを記録するコード例。
以上です。