トレースバック/ sys.exc_info()値を変数に保存する方法は?


127

エラーの名前とトレースバックの詳細を変数に保存したい。これが私の試みです。

import sys
try:
    try:
        print x
    except Exception, ex:
        raise NameError
except Exception, er:
    print "0", sys.exc_info()[0]
    print "1", sys.exc_info()[1]
    print "2", sys.exc_info()[2]

出力:

0 <type 'exceptions.NameError'>
1 
2 <traceback object at 0xbd5fc8>

望ましい出力:

0 NameError
1
2 Traceback (most recent call last):
  File "exception.py", line 6, in <module>
    raise NameError

PS私はこれがtracebackモジュールを使用して簡単にできることを知っていますが、ここではsys.exc_info()[2]オブジェクトの使用法を知りたいです。


sys.exc_info()[x] .__ str __()を印刷してみましたか?
zmbq

3
プログラムで何が起こっているのかを誤解している可能性があります。「sys.exc_info()[2]オブジェクト」と呼ぶのは、トレースバックオブジェクトのインスタンスです(=トレースバックモジュールをすでに使用しています)。これで、トレースバックモジュールのヘルパー関数を使用せずにそのオブジェクトを操作できますが、それでもまだ使用しているという事実は変わりません。:)
mac

1
@macは、ヘルパー関数を使用して、または使用せずに、このオブジェクトから値にアクセスする方法を教えてください。
codersofthedark

1
@dragosrsupercool-以下の私の回答で述べたように、トレースバックのドキュメントをご覧ください。データをテキストで取得する方法の例を示しましたが、例外名、コードの行などを抽出できるオブジェクトの他のメソッドがあります。正しい方法は、実際に操作する方法によって異なりますその後の値...
Mac

1
別の質問に対する私の回答は、詳細を説明するのに役立ちます-リンク付き!缶詰の文字列の場合、標準ライブラリのトレースバックモジュールは問題ないようです。詳細を知りたい場合は、ソース(<python install path>/Lib/traceback.py)で詳細を確認してください。
pythonlarry 2013

回答:


180

これが私のやり方です:

>>> import traceback
>>> try:
...   int('k')
... except:
...   var = traceback.format_exc()
... 
>>> print var
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ValueError: invalid literal for int() with base 10: 'k'

ただし、後で変数を処理する方法に応じて、より適切なメソッドが見つかる可能性があるため、トレースバックのドキュメントを確認する必要があります...


1
トレースバックモジュールを使用しない方法を探していました。このオブジェクト参照からトレースバックの詳細を出力できる方法はありますか?sys.exc_info()[2]
codersofthedark

そうです、私がsys.exc_info()[2] .format_exc()のようなことができると思ったのはそのためですが、これは機能しません。 [2]。何か案が?
codersofthedark

1
sys.exc_info()[2] .tb_textでフォローエラーが発生します-> AttributeError: 'traceback'オブジェクトに属性 'tb_text'がありません
codersofthedark

4
@dragosrsupercool- sys.exc_info()[2].tb_frame.f_code.co_names[3]、しかしそれはまったく意味がありません... traceback標準ライブラリで呼び出されたモジュールがある場合、それには理由があります... :)
mac

2
@codersofthedark traceback.format_exception(*sys.exc_info())がその方法です。ただし、機能的にはと同等traceback.format_exc()です。
wizzwizz4 2017

25

sys.exc_info()は、3つの値(type、value、traceback)を持つタプルを返します。

  1. ここでtypeは、処理される例外の例外タイプを取得します
  2. valueは、例外クラスのコンストラクターに渡される引数です
  3. トレースバックには、例外が発生した場所などのスタック情報が含まれています。

たとえば、次のプログラムでは

try:

    a = 1/0

except Exception,e:

    exc_tuple = sys.exc_info()

タプルを出力すると、値は次のようになります。

  1. exc_tuple [0]の値は「ZeroDivisionError」になります
  2. exc_tuple [1]の値は「整数除算またはゼロによるモジュロ」になります(例外クラスにパラメーターとして渡される文字列)
  3. exc_tuple [2]の値が「になり(一部のメモリアドレス)にトラックバック・オブジェクト

上記の詳細は、例外を文字列形式で出力するだけでも取得できます。

print str(e)

Python3の場合、exc_tuple [1](別名値)は例外のインスタンスであり、「パラメータとして渡される文字列」ではありません。参照:docs.python.org/3/library/sys.html#sys.exc_info
Shi

それは「例外としてのe:以外」ではないのですか?
Henrik

20

traceback.extract_stack()モジュール名、関数名、行番号に簡単にアクセスしたい場合に使用します。

出力の''.join(traceback.format_stack())ように見える文字列だけが必要な場合に使用しtraceback.print_stack()ます。

でもでお知らせ''.join()しますの要素から、複数行の文字列を取得しますformat_stack()含まれて\n。以下の出力を参照してください。

を忘れないでくださいimport traceback

これがからの出力ですtraceback.extract_stack()。読みやすくするためにフォーマットを追加しました。

>>> traceback.extract_stack()
[
   ('<string>', 1, '<module>', None),
   ('C:\\Python\\lib\\idlelib\\run.py', 126, 'main', 'ret = method(*args, **kwargs)'),
   ('C:\\Python\\lib\\idlelib\\run.py', 353, 'runcode', 'exec(code, self.locals)'),
   ('<pyshell#1>', 1, '<module>', None)
]

これがからの出力です''.join(traceback.format_stack())。読みやすくするためにフォーマットを追加しました。

>>> ''.join(traceback.format_stack())
'  File "<string>", line 1, in <module>\n
   File "C:\\Python\\lib\\idlelib\\run.py", line 126, in main\n
       ret = method(*args, **kwargs)\n
   File "C:\\Python\\lib\\idlelib\\run.py", line 353, in runcode\n
       exec(code, self.locals)\n  File "<pyshell#2>", line 1, in <module>\n'

4

例外ハンドラーから例外オブジェクトまたはトレースバックオブジェクトを取り出すときは、循環参照gc.collect()が発生し、収集に失敗するため、注意してください。これは、トレースバックオブジェクトが適切なタイミングでクリアされずgc.collect()finallyセクション内の明示的な呼び出しでさえ何も実行しないipython / jupyterノートブック環境で特に問題があるようです。そして、そのためにメモリが回収されない巨大なオブジェクトがいくつかある場合、それは大きな問題です(たとえば、CUDAのメモリ不足例外で、このソリューションを使用しないと、完全なカーネルの再起動で回復する必要があります)。

一般に、トレースバックオブジェクトを保存する場合は、次のlocals()ように、への参照からオブジェクトをクリアする必要があります。

import sys, traceback, gc
type, val, tb = None, None, None
try:
    myfunc()
except:
    type, val, tb = sys.exc_info()
    traceback.clear_frames(tb)
# some cleanup code
gc.collect()
# and then use the tb:
if tb:
    raise type(val).with_traceback(tb)

jupyter Notebookの場合、少なくとも例外ハンドラ内で行う必要があります。

try:
    myfunc()
except:
    type, val, tb = sys.exc_info()
    traceback.clear_frames(tb)
    raise type(val).with_traceback(tb)
finally:
    # cleanup code in here
    gc.collect()

Python 3.7でテスト済み。

PSのipythonまたはjupyterノートブックの環境の問題は%tb、トレースバックを保存し、後でいつでも利用できるようにする魔法があることです。その結果locals()、ノートブックが終了するか、別の例外によって以前に保存されたバックトレースが上書きされるまで、トレースバックに参加しているすべてのフレームは解放されません。これは非常に問題があります。フレームをクリーニングせずにトレースバックを保存しないでください。ここで修正を送信しました


3

オブジェクトはException.with_traceback()関数のパラメーターとして使用できます。

except Exception as e:
    tb = sys.exc_info()
    print(e.with_traceback(tb[2]))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.