web-dev-qa-db-ja.com

ネストされたtry / exceptブロックで例外を再発生させる方法は?

例外を再度発生させたい場合は、それぞれのraiseブロックで引数なしでexceptを使用するだけです。しかし、次のようなネストされた式が与えられた場合

try:
    something()
except SomeError as e:
    try:
        plan_B()
    except AlsoFailsError:
        raise e  # I'd like to raise the SomeError as if plan_B()
                 # didn't raise the AlsoFailsError

スタックトレースを中断せずにSomeErrorを再レイズするにはどうすればよいですか?この場合、raiseだけで最新のAlsoFailsErrorが再レイズされます。または、この問題を回避するためにコードをどのようにリファクタリングできますか?

73
Tobias Kienzler

例外のタイプ、値、およびトレースバックをローカル変数に保存し、 引数形式のraise を使用できます。

try:
    something()
except SomeError:
    t, v, tb = sys.exc_info()
    try:
        plan_B()
    except AlsoFailsError:
        raise t, v, tb

Python 3では、トレースバックは例外に保存されるため、raise eは(ほとんど)正しいことを行います:

try:
    something()
except SomeError as e:
    try:
        plan_B()
    except AlsoFailsError:
        raise e

上記の唯一の問題は、SomeErrorの処理中にAlsoFailsErrorが発生したことを示すわずかに誤解を招くトレースバックを生成することです(raise e内部except AlsoFailsError)、実際にはほぼ正反対が発生しました-AlsoFailsErrorからの回復を試みている間にSomeErrorを処理しました。この動作を無効にし、AlsoFailsErrorに言及しないトレースバックを取得するには、raise e with raise e from None

88
user4815162342

承認されたソリューション が正しい場合でも、Python2 + 3ソリューションを持つ Six ライブラリを指すのは良いことです、 six.reraise を使用します。

six。reraiseexc_typeexc_valueexc_traceback=なし)

おそらく別のトレースバックを使用して、例外をリレイズします。 [...]

だから、あなたは書くことができます:

import six


try:
    something()
except SomeError:
    t, v, tb = sys.exc_info()
    try:
        plan_B()
    except AlsoFailsError:
        six.reraise(t, v, tb)
15
Laurent LAPORTE

Drew McGowenの提案 に従いますが、一般的なケース(戻り値sが存在する場合)を処理する場合、 ser4815162342の答え の代わりになります:

try:
    s = something()
except SomeError as e:
    def wrapped_plan_B():
        try:
            return False, plan_B()
        except:
            return True, None
    failed, s = wrapped_plan_B()
    if failed:
        raise
8
Tobias Kienzler

とにかくPython 3.5+はトレースバック情報をエラーに添付するため、個別に保存する必要はなくなりました。

>>> def f():
...   try:
...     raise SyntaxError
...   except Exception as e:
...     err = e
...     try:
...       raise AttributeError
...     except Exception as e1:
...       raise err from None
>>> f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 9, in f
  File "<stdin>", line 3, in f
SyntaxError: None
>>> 
3