Python で例外のエラーメッセージを取得するコード例

Python

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)

(Python) class type(object)

変数 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) class type(object)

コード例

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) sys.exc_info()

(Python) try 文 – 『sys.exc_info() は、例外クラス、例外インスタンス、そして例外が発生したプログラム上の位置を識別するトレースバックオブジェクト (標準型の階層 を参照してください) の 3 要素からなるタプルを返します。』

(Python) 引数リストのアンパック (Unpacking Argument Lists)

(Python) pprint.pprint(object, stream=None, indent=1, width=80, depth=None, *, compact=False, sort_dicts=True)

コード例

"""『エラーメッセージ全体』の『リスト』を取得"""
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 BaseExceptionargs, with_traceback(tb)

(Python) 組み込み例外 – 具象例外 – exception UnicodeErrorencoding, 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)

(Python) raise 文(レイズ ぶん)

自作例外のメッセージを取得

やり方は『組み込み例外』のときと同じでした。

コード例

"""自作した例外のエラーメッセージを取得するコード例 (ユーザー定義例外)"""
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 でログを記録するコード例。

以上です。

スポンサーリンク
シェアする(押すとSNS投稿用の『編集ページ』に移動します)
フォローする(RSSフィードに移動します)
スポンサーリンク
シラベルノート
タイトルとURLをコピーしました