web-dev-qa-db-ja.com

Python例外を再発生させ、スタックトレースを保持する

スレッドで例外をキャッチし、メインスレッドで再発生させようとしています。

import threading
import sys

class FailingThread(threading.Thread):
    def run(self):
        try:
            raise ValueError('x')
        except ValueError:
            self.exc_info = sys.exc_info()

failingThread = FailingThread()
failingThread.start()
failingThread.join()

print failingThread.exc_info
raise failingThread.exc_info[1]

これは基本的に機能し、次の出力を生成します。

(<type 'exceptions.ValueError'>, ValueError('x',), <traceback object at 0x1004cc320>)
Traceback (most recent call last):
  File "test.py", line 16, in <module>
    raise failingThread.exc_info[1]

ただし、例外のソースは、再レイズが発生した16行目を指しています。元の例外は7行目です。出力が次のようになるようにmainスレッドを変更するにはどうすればよいですか。

Traceback (most recent call last):
  File "test.py", line 7, in <module>
54
roskakori

Python 2では、3つの引数すべてを使用してレイズする必要があります。

_raise failingThread.exc_info[0], failingThread.exc_info[1], failingThread.exc_info[2]
_

トレースバックオブジェクトを3番目の引数として渡すと、スタックが保持されます。

help('raise')から:

Noneではなく3番目のオブジェクトが存在する場合、それはトレースバックオブジェクトである必要があります(セクションを参照してください)標準型階層)、および例外が発生した場所として、現在の場所の代わりに使用されます。 3番目のオブジェクトが存在し、トレースバックオブジェクトまたはNoneではない場合、TypeError例外が発生します。 raiseの3つの式の形式は、except句で透過的に例外を再発生させるのに役立ちますが、再発生する例外が最も多かった場合は、式のないraiseを推奨します。現在のスコープで最近アクティブな例外。

この特定のケースでは、no expressionバージョンを使用できません。

Python 3(コメントどおり)3の場合:

_raise failingThread.exc_info[1].with_traceback(failingThread.exc_info[2])
_

または、単純に_raise ... from ..._を使用して例外を連鎖させることができますが、cause属性に接続された元のコンテキストで連鎖例外が発生しますが、これは必要な場合とそうでない場合があります。

51
Duncan

このコードスニペットは、python 2&3の両方で機能します。

      1 try:
----> 2     raise KeyError('Default key error message')
      3 except KeyError as e:
      4     e.args = ('Custom message when get re-raised',) #The comma is not a typo, it's there to indicate that we're replacing the Tuple that e.args pointing to with another Tuple that contain the custom message.
      5     raise
1
Steven Than

次のように書いてもらえますか:

try:
    raise ValueError('x')
except ValueError as ex:
    self.exc_info = ex

そして、例外からのスタックトレースを使用しますか?

0
Ivaylo Petrov