Pythonの「レイズ」の使用法


196

違いは何だraiseraise fromPythonでは?

try:
    raise ValueError
except Exception as e:
    raise IndexError

これは

Traceback (most recent call last):
  File "tmp.py", line 2, in <module>
    raise ValueError
ValueError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "tmp.py", line 4, in <module>
    raise IndexError
IndexError

そして

try:
    raise ValueError
except Exception as e:
    raise IndexError from e

これは

Traceback (most recent call last):
  File "tmp.py", line 2, in <module>
    raise ValueError
ValueError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "tmp.py", line 4, in <module>
    raise IndexError from e
IndexError

9
PEP-3134を読みましたか?
jonrsharpe 14

4
raise IndexError from None、と言ってください。
Martijn Pieters

11
へえ。raise IndexError from False上げTypeError、ありませんIndexError。私の日を作りました。
Mad Physicist


ここが適切な場所かどうかはわかりませんが、Spyderを使用しているすべての人にとって:この構造全体はそこで機能しません。これは3年以上の間問題になっていますが(github.com/spyder-ide/spyder/issues/2943)、チェーンされた例外は必要ないと考えているようです。
Emil Bode

回答:


227

違いは、を使用するfromと、__cause__属性が設定され、例外がによって直接発生したことを示すメッセージが表示されることです。を省略した場合from、no __cause__が設定され__context__ますが、属性も設定される可能性があり、トレースバックは、他の処理中に発生したコンテキストを表示します。

例外ハンドラーで__context__使用raiseした場合、設定は発生します。raise他の場所で使用した場合も__context__設定されません。

a __cause__が設定されている場合、__suppress_context__ = Trueフラグも例外に設定されます。とき__suppress_context__に設定されTrue__context__トレースバックを印刷する際に無視されます。

コンテキストを表示したくない(別の例外発生メッセージの処理中にを使用したくない)例外ハンドラーから発生する場合、をに設定します。raise ... from None__suppress_context__True

つまり、Pythonは例外にコンテキストを設定するので、例外が発生した場所をイントロスペクトして、別の例外が例外に置き換えられたかどうかを確認できます。原因を例外に追加して、トレースバックを他の例外について明示的にすることもできます(別の表現を使用)。コンテキストは無視されます(ただし、デバッグ時にイントロスペクトできます)。を使用raise ... from Noneすると、印刷されるコンテキストを抑制できます。

raiseステートメントのドキュメントを参照してください

from句は、例外チェーンのために使用される:与えられた場合、第二式は次にとして発生した例外に付着される別の例外クラスまたはインスタンスでなければならない__cause__(書き込み可能な)属性。発生した例外が処理されない場合、両方の例外が出力されます。

>>> try:
...     print(1 / 0)
... except Exception as exc:
...     raise RuntimeError("Something bad happened") from exc
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: int division or modulo by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened

例外が例外ハンドラーまたはfinally句内で発生した場合、同様のメカニズムが暗黙的に機能し__context__ます。次に、前の例外が新しい例外の属性としてアタッチされます。

>>> try:
...     print(1 / 0)
... except:
...     raise RuntimeError("Something bad happened")
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: int division or modulo by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened

コンテキストの詳細と例外に付随する原因情報については、組み込みの例外のドキュメントも参照してください。


11
明示的に使用して例外をチェーンに何らかの理由があるfrom__cause__暗黙的の代わりには__context__?がキャッチした例外とは異なる例外をアタッチするケースはありますexceptか?
darkfeline 2014

13
@darkfeline:データベースAPIがWebやディスクなどのさまざまなソースからのデータベースを開くことをサポートしているとしましょう。データベースのオープンに失敗した場合、APIは常にを発生させDatabaseErrorます。ただしIOError、ファイルのオープンに失敗したHTTPErrorため、またはURLが機能しなかったために失敗の結果である場合、それは明示的に含めたいコンテキストであるため、APIを使用する開発者はこれがなぜであるかをデバッグできます。その瞬間にあなたは使いますraise DatabaseError from original_exception
Martijn Pieters

4
@darkfeline:その開発者は、独自のAPIのデータベースAPIの使用をラップし、その上で渡したいされている場合IOErrorまたはHTTPError上へ彼らの消費者は、彼らが使用する必要があると思いraise NewException from databaseexception.__cause__、今から別の例外を使用して、DatabaseException彼らはただ巻き込まこと。
Martijn Pieters

2
@ dan3:いいえ、ありません。例外チェーンは純粋にPython 3の機能です。
Martijn Pieters

5
@ laike9m:例外を処理しているときにfoo新しい例外を発生させたいbarですか?次に、使用raise bar from fooして、foo 直接原因barとなったPython状態を取得できます。あなたがいる場合はありません使用しfrom foo、その後、Pythonはまだ両方を出力しますが、その状態の取り扱いの際にfoobar育った、さまざまなメッセージは、このフラグへのエラー処理で可能なバグを意図しました。
Martijn Pieters
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.