В 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