我的一些api观点有这样的内容:
try:
do_stuff()
except KeyError as exc:
logger.log(exc)
raise APIException("No good")
理想情况下,我不希望像这样登录每一段代码,但使用捕获APIException的常规异常处理程序,因此我将代码更改为:
try:
do_stuff()
except KeyError as exc:
raise APIException(exc)
def exception_handler(...):
logger.log(exc) # I want to log the KeyError...
return Response({"message": "try again sam"}, status_code=400)
我的问题是处理程序中的exc不是keyerror而是apiexception,我可以以某种方式从sys.exc_info或stacktrace获取KeyError吗?
答案 0 :(得分:0)
好的做法是提出自己的异常(此处为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))
这个解决方案是最好的,IMO。
答案 1 :(得分:0)
由于您使用的是Python 3,因此只需引发APIException
:
try:
do_stuff()
except KeyError as exc:
raise APIException() from exc
然后在您的异常处理程序中,如果exc
是APIException
,则可以使用exc.__context__
访问原始异常。
def exception_handler(exc):
logger.log(exc.__context__)
return Response({"message": "try again sam"}, status_code=400)
from exc
实际上并不需要能够访问__context__
,但它清楚地表明KeyError
已转换为APIException
,而不是APIException
在处理KeyError
期间被提出。
有关详细信息,请参阅exception docs。