捕获Python中的嵌套异常

时间:2017-06-03 03:03:28

标签: python error-handling nested

我有一组Python脚本,它们以嵌套的方式调用函数。对于这些函数中的每一个,我都有一个try,除了语句来捕获每个异常并打印它们。我想发送一封电子邮件警报,其中包含执行期间遇到的完整异常序列。例如:

import sys

def SendAlert(ErrorMessage):
    try:
        #send email alert with error message
        #[...]
    except:
        print(str(sys.exc_info()))
        return(sys.exc_info())

def ParentFunction():
    try:
        #call ChildFunction
        ChildResult = ChildFunction()

        #do stuff with ChildResult
        #[...]
        return ParentResult
    except:
        ErrorMessage = str(sys.exc_info())
        print(ErrorMessage)
        SendAlert(ErrorMessage)

def ChildFunction():
    try:
        #do stuff
        #[...]
        return ChildResult
    except:
        print(str(sys.exc_info()))
        return(sys.exc_info())

#main
if __name__ == '__main__':
    Result = ParentFunction()

如果ChildFunction中出现错误,上面的代码将表现如下,这是最嵌套的函数:

  • ChildFunction遇到异常,它将打印并返回 向ParentFunction
  • 的错误消息
  • ParentFunction将失败,因为ChildResult包含错误消息而非有效值
  • ParentFunction将触发和例外并在电子邮件警报中发送自己的错误消息

除了ParentFunction的错误消息之外,我希望电子邮件提醒包含来自ChildFunction的错误消息。请注意,我想避免在ChildResult的except语句中将SendAlert变量传递给ParentFunction函数,因为在现实生活中我的程序有很多嵌套函数,这意味着传递结果将每个函数的变量放入except语句中。

你将如何实现这一目标?有没有办法访问整个程序触发的完整错误序列?

由于

2 个答案:

答案 0 :(得分:4)

您不需要返回使用sys.exc_info获得的异常:我们可以重新提升它

try:
    # do stuff
# FIXME: we should avoid catching too broad exception
except Exception as err:
    # do stuff with exception
    raise err

所以你的例子看起来像

def SendAlert(ErrorMessage):
    try:
        # send email alert with error message
        # [...]
        pass
    # what kind of exceptions may occur while sending email?
    except Exception as err:
        print(err)
        raise err


def ParentFunction():
    try:
        # call ChildFunction
        ChildResult = ChildFunction()

        ParentResult = ChildResult
        # do stuff with ChildResult
        # [...]
        return ParentResult
    # FIXME: we should avoid catching too broad exception
    except Exception as err:
        ErrorMessage = str(err)
        # why do we need to print again?
        print(ErrorMessage)
        SendAlert(ErrorMessage)


def ChildFunction():
    try:
        ChildResult = 0
        # do stuff
        # [...]

        # let's raise `ZeroDivisionError`

        ChildResult /= 0

        return ChildResult
    # FIXME: we should avoid catching too broad exception
    except Exception as err:
        print(err)
        raise err


# main
if __name__ == '__main__':
    Result = ParentFunction()

进一步改进

对于打印完整错误回溯,我们可以使用logging模块,如

import logging

logging.basicConfig(level=logging.DEBUG)

logger = logging.getLogger(__name__)


def SendAlert(ErrorMessage):
    try:
        # send email alert with error message
        # [...]
        pass
    # what kind of exceptions may occur while sending email?
    except Exception as err:
        logger.exception('Error while sending email')
        # we're not receiving values from this function
        raise err


def ParentFunction():
    try:
        # call ChildFunction
        ChildResult = ChildFunction()

        ParentResult = ChildResult
        # do stuff with ChildResult
        # [...]
        return ParentResult
    # FIXME: we should avoid catching too broad exception
    except Exception as err:
        # this will log full error traceback
        # including `ChildFunction`
        logger.exception('Error in ParentFunction')
        ErrorMessage = str(err)
        SendAlert(ErrorMessage)


def ChildFunction():
    ChildResult = 0
    # do stuff
    # [...]

    # e. g. let's raise `ZeroDivisionError`
    ChildResult /= 0

    return ChildResult


# main
if __name__ == '__main__':
    Result = ParentFunction()

这只是冰山一角,logging太棒了,你绝对应该使用它。

进一步阅读

答案 1 :(得分:1)

您还可以创建一个custom exception,可以收到描述性错误消息并将其返回。

这是一个简单的例子,您可以修改并将其实现到您的代码中,直到它满足您的需求:

class MyCustomError(Exception):
    def __init__(self, err):
        Exception.__init__(self)
        self.error = err
    def __str__(self):
        return "%r" % self.error

a = 1
try:
    if a != 0:
        raise MyCustomError("This is an Error!")
except MyCustomError as err:
    print(err)

输出:

'This is an Error!'