68

私はこれに似たコードを持っています:

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 __name__ == '__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
4

5 に答える 5

116

空白raiseは最後の例外を発生させます。

# need to re-raise err so caller can do its own handling
if err:
    raise

raise somethingPythonを使用している場合something、直前にキャッチされた例外なのか、新しいスタックトレースを使用した新しい例外なのかを知る方法はありません。raiseそのため、スタックトレースを保持する空白があります。

ここで参照

于 2011-01-28T05:51:40.420 に答える
68

例外を変更して再スローすることができます。

式が存在しない場合はraise、現在のスコープでアクティブだった最後の例外を再発生させます。現在のスコープでアクティブな例外がない場合はTypeError、これがエラーであることを示す例外が発生します(IDLEで実行している場合は、Queue.Empty代わりに例外が発生します)。

それ以外の場合は、省略された式の値としてraise使用して、式を評価して3つのオブジェクトを取得します 。None最初の2つのオブジェクトは、例外のタイプと値を判別するために使用されます。

3番目のオブジェクトが存在し、存在しない場合None、それはトレースバックオブジェクトである必要があり(「標準タイプ階層」のセクションを参照)、現在の場所の代わりに、例外が発生した場所として置き換えられます。3番目のオブジェクトが存在し、トレースバックオブジェクトまたはNoneではない場合、TypeError例外が発生します。

の3つの式の形式は、句でraise例外を透過的に再発生させるのに役立ちますが、 再発生する例外が現在のスコープで最後にアクティブな例外である場合は、式を使用しないことをお勧めします。exceptraise

したがって、例外を変更して再スローする場合は、次のように実行できます。

try:
    buggy_code_which_throws_exception()
except Exception as e:
    raise Exception, "The code is buggy: %s" % e, sys.exc_info()[2]
于 2013-01-04T18:03:42.477 に答える
7

トレースバックモジュール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 __name__ == '__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
于 2011-01-28T05:48:49.213 に答える
5

@Jochenの答えは単純なケースではうまく機能しますが、直接キャッチして再スローしない、より複雑なケースを処理することはできませんが、何らかの理由でオブジェクトとして例外が与えられ、完全に再スローしたい場合があります新しいコンテキスト(つまり、別のプロセスで処理する必要がある場合)。

この場合、私は次のことを提案します。

  1. 元のexc_infoを取得します
  2. スタックトレースを使用して、元のエラーメッセージをフォーマットします
  3. その完全なエラーメッセージ(スタックトレースを含む)が埋め込まれた新しい例外をスローします

これを行う前に、後で再スローする新しい例外タイプを定義してください...

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)
于 2017-04-11T00:42:48.517 に答える
2

主な関数は次のようになっている必要があります。

def main():
    try:
        func1()
    except Exception, err:
        # error processing
        raise

これは、エラーを処理(および再発生)する標準的な方法です。これがコードパッドのデモンストレーションです。

于 2011-01-28T05:50:44.787 に答える