次のようなコードがあります。
import sys
def func1():
func2()
def func2():
raise Exception('test error')
def main():
err = None
try:
func1()
except:
err = sys.exc_info()[1]
pass
# some extra processing, involving checking err details (if err is not None)
# need to re-raise err so caller can do its own handling
if err:
raise err
if __== '__main__':
main()
いつ func2
は、次のトレースバックを受け取る例外を発生させます。
Traceback (most recent call last):
File "err_test.py", line 25, in <module>
main()
File "err_test.py", line 22, in main
raise err
Exception: test error
ここから、例外がどこから来ているのかわかりません。元のトレースバックは失われます。
元のトレースバックを保存して再レイズするにはどうすればよいですか?私はこれに似たものを見たいです:
Traceback (most recent call last):
File "err_test.py", line 26, in <module>
main()
File "err_test.py", line 13, in main
func1()
File "err_test.py", line 4, in func1
func2()
File "err_test.py", line 7, in func2
raise Exception('test error')
Exception: test error
空白のraise
は、最後の例外を発生させます。
# need to re-raise err so caller can do its own handling
if err:
raise
raise something
Pythonを使用すると、something
が直前にキャッチされた例外であるか、新しいスタックトレースを持つ新しい例外であるかを知る方法がありません。スタックトレースを保持する空白のraise
です。
変更および再スロー 例外が可能です:
式が存在しない場合、
raise
は現在のスコープでアクティブだった最後の例外を再発生させます。現在のスコープでアクティブな例外がない場合、これがエラーであることを示すTypeError
例外が発生します(IDLEで実行している場合は、Queue.Empty
例外が代わりに発生します)。それ以外の場合、
raise
は、省略された式の値としてNone
を使用して、3つのオブジェクトを取得する式を評価します。最初の2つのオブジェクトは、例外のタイプと値を決定するために使用されます。
None
ではなく3番目のオブジェクトが存在する場合、それはトレースバックオブジェクトである必要があり(セクション標準型階層を参照)、例外が発生した場所として現在の場所の代わりに置き換えられます。 3番目のオブジェクトが存在し、トレースバックオブジェクトまたはNone
ではない場合、TypeError
例外が発生します。
raise
の3つの式の形式は、except
句で例外を透過的に再発生させるのに役立ちますが、例外を再実行する場合は、式のないraise
を優先する必要があります。 -raisedは、現在のスコープで最後にアクティブになった例外です。
したがって、例外を変更して再スローする場合は、次の操作を実行できます。
try:
buggy_code_which_throws_exception()
except Exception as e:
raise Exception, "The code is buggy: %s" % e, sys.exc_info()[2]
traceback モジュールとともにsys.exc_info()
を介して、例外に関する多くの情報を取得できます。
コードに次の拡張機能を試してください。
import sys
import traceback
def func1():
func2()
def func2():
raise Exception('test error')
def main():
try:
func1()
except:
exc_type, exc_value, exc_traceback = sys.exc_info()
# Do your verification using exc_value and exc_traceback
print "*** print_exception:"
traceback.print_exception(exc_type, exc_value, exc_traceback,
limit=3, file=sys.stdout)
if __== '__main__':
main()
これは、あなたが望むものと同様に印刷されます。
*** print_exception:
Traceback (most recent call last):
File "err_test.py", line 14, in main
func1()
File "err_test.py", line 5, in func1
func2()
File "err_test.py", line 8, in func2
raise Exception('test error')
Exception: test error
@Jochenの答えは単純な場合にはうまく機能しますが、より複雑なケースを処理することはできません。新しいコンテキスト(つまり、別のプロセスで処理する必要がある場合)。
この場合、以下を提案します。
これを行う前に、後で再スローする新しい例外タイプを定義してください...
class ChildTaskException(Exception):
pass
問題のあるコードでは...
import sys
import traceback
try:
# do something dangerous
except:
error_type, error, tb = sys.exc_info()
error_lines = traceback.format_exception(error_type, error, tb)
error_msg = ''.join(error_lines)
# for example, if you are doing multiprocessing, you might want to send this to another process via a pipe
connection.send(error_msg)
再スロー...
# again, a multiprocessing example of receiving that message through a pipe
error_msg = pcon.recv()
raise ChildTaskException(error_msg)
メイン関数は次のようにする必要があります。
def main():
try:
func1()
except Exception, err:
# error processing
raise
これは、エラーを処理(および再発生)する標準的な方法です。 これはコードパッドのデモです。