【问题标题】:Python catch previous exception in broad handlerPython 在广泛的处理程序中捕获先前的异常
【发布时间】:2018-10-14 23:56:10
【问题描述】:

我的一些 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)

exception_handler.py

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 吗?

【问题讨论】:

  • 您可以尝试logger.log(exc.args[0]),因为 KeyError 已传递给 APIException 构造函数。但是,如果您有不同的异常接收级别,您将不得不做更多的工作。

标签: python django python-3.x django-rest-framework


【解决方案1】:

最好的做法是引发您自己的异常(这里是APIException)并附加原始异常。

您可以查看six.raise_from(如果您想要兼容 Python 2/3 的解决方案):

从上下文中引发异常。在 Python 3 上,这相当于 raise exc_value from exc_value_from。在不支持异常链的 Python 2 上,相当于 raise 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。

【讨论】:

    【解决方案2】:

    由于您使用的是 Python 3,您可以简单地提出APIException

    try:
        do_stuff()
    except KeyError as exc:
        raise APIException() from exc
    

    然后在您的异常处理程序中,如果excAPIException,您可以使用exc.__context__ 访问原始异常。

    def exception_handler(exc):
        logger.log(exc.__context__)
        return Response({"message": "try again sam"}, status_code=400)
    

    from exc 实际上并不需要能够访问__context__,但它清楚地表明KeyError 已转换为APIException,而不是在处理@987654333 期间引发APIException @。 请参阅exception docs 了解更多信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-05-02
      • 1970-01-01
      • 2015-10-02
      • 1970-01-01
      • 2014-09-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多