Ответ 1
В Python 2.x малоизвестная особенность raise
заключается в том, что ее можно использовать не более чем с одним аргументом: форма с тремя аргументами raise
принимает тип исключения, экземпляр исключения и Выслеживать. Вы можете получить трассировку с помощью sys.exc_info()
, которая возвращает (не случайно) тип исключения, экземпляр исключения и трассировку.
(Причина, по которой рассматривается тип исключения и экземпляр исключения как два отдельных аргумента, является артефактом из дней перед классами исключений.)
Итак:
import sys
class MyError(Exception):
pass
def try_except(fn):
def wrapped(*args, **kwargs):
try:
return fn(*args, **kwargs)
except Exception, e:
et, ei, tb = sys.exc_info()
raise MyError, MyError(e), tb
return wrapped
def bottom():
1 / 0
@try_except
def middle():
bottom()
def top():
middle()
>>> top()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "tmp.py", line 24, in top
middle()
File "tmp.py", line 10, in wrapped
return fn(*args, **kwargs)
File "tmp.py", line 21, in middle
bottom()
File "tmp.py", line 17, in bottom
1 / 0
__main__.MyError: integer division or modulo by zero
В Python 3 это немного изменилось. Там трассировки привязаны к экземпляру исключения, и у них есть метод with_traceback
:
raise MyError(e).with_traceback(tb)
С другой стороны, у Python 3 также есть цепочка исключений, что имеет большее значение во многих случаях; Чтобы использовать это, вы просто используете:
raise MyError(e) from e