Хорошей практикой является поднятие собственного исключения (здесь оно APIException
) и добавление исходного исключения.
Вы можете взглянуть на six.raise_from (если вы хотите решение, совместимое с Python 2/3):
Вызовите исключение из контекста. На Python 3 это эквивалентно raise exc_value from exc_value_from
. В Python 2, который не поддерживает цепочку исключений, это эквивалентно повышению exc_value.
Вы также можете создать свой собственный класс исключений, который может выполнять цепочку.
class APIException(Exception):
def __init__(self, msg, exc_from=None):
self.exc_from = exc_from
if exc_from:
msg += ': raise from {0}'.format(str(exc_from))
super(APIException, self).__init__(self, msg)
# demo
def do_stuff():
raise KeyError('bad key')
def main():
try:
do_stuff()
except KeyError as exc:
raise APIException('error in main', exc)
try:
main()
except APIException as exc:
print(str(exc))
Конечно, вместо того, чтобы печатать / регистрировать ваше сообщение об ошибке APIException, вы можете записать свое исходное сообщение:
try:
main()
except APIException as exc:
print(str(exc.exc_from))
Редактировать: использовать иерархию классов для исключений
Но, если do_stuff()
является частью вашего API, лучше выполнять обработку исключений внутри этой функции и генерировать собственное исключение, которое может наследовать APIException
.
class APIException(Exception):
pass
class BadStuffError(APIException):
pass
def do_stuff():
try:
# ...
raise KeyError('bad key')
except KeyError as exc:
raise BadStuffError('bad stuff: ' + exc.args[0])
def main():
do_stuff()
try:
main()
except APIException as exc:
print(str(exc))
Это лучшее решение, ИМО.