1. ホーム
  2. python

[解決済み] 例外オブジェクトからトレースバック情報を抽出する

2022-05-13 13:29:58

質問

(起源が不明な) Exception オブジェクトが与えられたとき、そのトレースバックを取得する方法はあるでしょうか。私はこのようなコードを持っています。

def stuff():
   try:
       .....
       return useful
   except Exception as e:
       return e

result = stuff()
if isinstance(result, Exception):
    result.traceback <-- How?

Exception オブジェクトからトレースバックを抽出するにはどうすればよいですか。

どのように解決するのですか?

この質問に対する答えは、使用しているPythonのバージョンに依存します。

Python 3では

単純な話です。例外には __traceback__ 属性があります。この属性は書き込みも可能であり、便利なことに with_traceback メソッドを使って設定できます。

raise Exception("foo occurred").with_traceback(tracebackobj)

これらの機能は、最小限の記述で raise のドキュメントの一部として、最小限に記述されています。

この部分の回答はすべて、Vyctorの功績によるものです。 がこの情報を最初に投稿した . 私は、この答えがトップに留まっていることと、Python 3がより一般的になってきていることから、ここにそれを含めています。

Python 2 では

うっとうしいほど複雑です。トレースバックの問題は、トレースバックがスタックフレームへの参照を持ち、スタックフレームが、スタックフレームへの参照を持つトレースバックへの参照を持つことです。 への参照を持つ... といった具合です。これはガベージコレクタの問題を引き起こします。(これは ecatmur に感謝します)。

これを解決する素晴らしい方法は、外科的に サイクルを中断する を残した後 except 節を抜けた後、のサイクルを中断します。Python 2の解決策はもっと醜いもので、アドホックな関数が提供されています。 sys.exc_info() というアドホックな関数が提供され、それは の中だけで動作します。 except . これは、現在処理されている例外の例外、例外の型、トレースバックを含むタプルを返します。

ですから、もしあなたが except 節にある場合、出力された sys.exc_info() と共に traceback モジュールと一緒に、様々な便利なことをすることができます。

>>> import sys, traceback
>>> def raise_exception():
...     try:
...         raise Exception
...     except Exception:
...         ex_type, ex, tb = sys.exc_info()
...         traceback.print_tb(tb)
...     finally:
...         del tb
... 
>>> raise_exception()
  File "<stdin>", line 3, in raise_exception

しかし、あなたの編集が示すように、あなたはトレースバックを得るために が発生した後に、例外が処理されなかった場合に表示されるトレースバックを取得しようとしているのです。 が発生した後に と表示されます。これはもっと難しい質問です。残念ながら sys.exc_info が返す (None, None, None) は、例外処理が行われていない場合です。その他の関連する sys 属性も役に立ちません。 sys.exc_traceback は非推奨で、例外が処理されない場合は未定義です。 sys.last_traceback は完璧に見えますが、対話型セッションの間だけ定義されるようです。

例外がどのように発生するかを制御できる場合は inspect カスタム例外 を追加して、情報の一部を保存することができます。しかし、それがどのように機能するかはまったくわかりません。

実を言うと、例外をキャッチして返すというのは、ちょっと珍しいことなんです。これは、とにかくリファクタリングが必要だというサインかもしれません。