Цепочки исключений Python
Существует ли стандартный способ использования цепочек исключений в Python? Как исключение Java, вызванное '?
Вот какой фон.
У меня есть модуль с одним основным классом исключений 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?
Ответы
Ответ 1
Цепочка исключений доступна только в 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)
Ответ 2
Это то, о чем вы просите?
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__
объекта исключения.)