143

(出所不明の) Exception オブジェクトが与えられた場合、そのトレースバックを取得する方法はありますか? 次のようなコードがあります。

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

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

トレースバックを取得したら、例外オブジェクトからトレースバックを抽出するにはどうすればよいですか?

4

6 に答える 6

115

この質問に対する答えは、使用しているPythonのバージョンによって異なります。

Python3の場合

簡単です。例外に__traceback__は、トレースバックを含む属性が備わっています。この属性も書き込み可能でありwith_traceback、例外の方法を使用して便利に設定できます。

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

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

回答のこの部分のすべてのクレジットは、この情報を最初に投稿したVyctorに送られる必要があります。この答えが一番上に留まっていて、Python 3がより一般的になっているという理由だけで、ここに含めています。

Python2の場合

それは厄介なほど複雑です。トレースバックの問題は、スタックフレームへの参照があり、スタックフレームには、への参照があるスタックフレームへの参照があるトレースバックへの参照があることです。これにより、ガベージコレクターに問題が発生します。(これを最初に指摘してくれたecatmurに感謝します。)

これを解決する良い方法は、Python 3が行うことである、句を離れた後に外科的にサイクルを中断することです。exceptPython 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)syssys.exc_tracebacksys.last_traceback

inspect例外の発生方法を制御できる場合は、カスタム例外を使用して一部の情報を格納できる可能性があります。しかし、それがどのように機能するかは完全にはわかりません。

実を言うと、例外をキャッチして返すことは、一種の珍しいことです。これは、とにかくリファクタリングする必要がある兆候かもしれません。

于 2012-07-10T14:08:57.633 に答える
91

Python 3.0 [PEP 3109]以降、組み込みクラスExceptionには(Python 3.2.3__traceback__の場合) を含む属性があります。traceback object

>>> try:
...     raise Exception()
... except Exception as e:
...     tb = e.__traceback__
...
>>> tb
<traceback object at 0x00000000022A9208>

問題は、しばらくグーグル__traceback__した後、いくつかの記事しか見つかりませんでしたが、__traceback__.

ただし、Python 3 のドキュメントにraiseは、次のように記載されています。

traceback オブジェクトは通常、例外が発生したときに自動的に作成され、__traceback__書き込み可能な属性としてアタッチされます。

したがって、使用することを意図していると思います。

于 2013-01-28T14:31:59.560 に答える
9

トレースバックが例外に保存されないのには十分な理由があります。トレースバックはそのスタックのローカル変数への参照を保持するため、循環 GC が開始されるまで、循環参照と (一時的な) メモリ リークが発生します (これが、トレースバックをローカル変数に格納してはならない理由です)。

私が考えることができる唯一のことは、それがキャッチしていると思われるときに、実際には特殊なタイプをキャッチしていて、例外が呼び出し元としてあなたに伝播するように、 monkeypatchstuffのグローバルにあなたがすることです:Exception

module_containing_stuff.Exception = type("BogusException", (Exception,), {})
try:
    stuff()
except Exception:
    import sys
    print sys.exc_info()
于 2012-07-10T16:00:44.430 に答える