web-dev-qa-db-ja.com

Python例外チェーン

Pythonで例外チェーンを使用する標準的な方法はありますか? Java exception 'caused by'?

ここに背景があります。

私は1つの主要な例外クラスDSErrorを持つモジュールを持っています:

 class DSError(Exception):
     pass

このモジュール内のどこかにあります:

try:
    v = my_dict[k]
    something(v)
except KeyError as e:
    raise DSError("no key %s found for %s" % (k, self))
except ValueError as e:
    raise DSError("Bad Value %s found for %s" % (v, self))
except DSError as e:
    raise DSError("%s raised in %s" % (e, self))

基本的に、このスニペットはDSErrorのみをスローし、何が起こったのか、なぜ起こったのかを教えてくれるはずです。問題は、tryブロックが他の多くの例外をスローする可能性があることです。したがって、次のようなことができるなら、私は好みます。

try:
    v = my_dict[k]
    something(v)
except Exception as e:
    raise DSError(self, v, e)  # Exception chained...

これは標準的なPythonの方法ですか?私は他のモジュールで例外チェーンを見ていませんでしたが、それはPythonでどのように行われますか?

73
Ayman

例外連鎖 は、Python 3でのみ使用できます。

try:
    v = {}['a']
except KeyError as e:
    raise ValueError('failed') from e

次のような出力が得られます

Traceback (most recent call last):
  File "t.py", line 2, in <module>
    v = {}['a']
KeyError: 'a'

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

Traceback (most recent call last):
  File "t.py", line 4, in <module>
    raise ValueError('failed') from e
ValueError: failed

ほとんどの場合、from;も必要ありません。 Python 3はデフォルトで、次のように例外処理中に発生したすべての例外を表示します。

Traceback (most recent call last):
  File "t.py", line 2, in <module>
    v = {}['a']
KeyError: 'a'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "t.py", line 4, in <module>
    raise ValueError('failed')
ValueError: failed

Python 2でできることは、次のようなカスタム属性を例外クラスに追加することです。

class MyError(Exception):
    def __init__(self, message, cause):
        super(MyError, self).__init__(message + u', caused by ' + repr(cause))
        self.cause = cause

try:
    v = {}['a']
except KeyError as e:
    raise MyError('failed', e)
106
phihag

これはあなたが求めているものですか?

class MyError(Exception):
    def __init__(self, other):
        super(MyError, self).__init__(other.message)

>>> try:
...     1/0
... except Exception, e:
...     raise MyError(e)
Traceback (most recent call last):
  File "<pyshell#27>", line 4, in <module>
    raise MyError(e)
MyError: division by zero

元の例外オブジェクトを保存する場合は、独自の例外クラスの__init__。例外オブジェクト自体は例外が発生した場所についてあまり有用な情報を提供しないため、トレースバックを実際に保存することができます。

class MyError(Exception):
    def __init__(self, other):
        self.traceback = sys.exc_info()
        super(MyError, self).__init__(other.message)

この後、例外のtraceback属性にアクセスして、元の例外に関する情報を取得できます。 (Python 3はこれを__traceback__例外オブジェクトの属性。

5
BrenBarn