Capture Nested Exceptions in Python
我有一组Python脚本,它们以嵌套的方式调用函数。对于这些函数中的每一个,我都有一个try,除了语句来捕获每个异常并打印它们。我想发送一封电子邮件警报,其中包含执行期间遇到的完整异常序列。例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 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 遇到异常,它将打印并返回
错误消息到ParentFunction -
ParentFunction 将失败,因为ChildResult 包含错误消息而不是有效值 -
ParentFunction 将触发和异常,并在电子邮件警报中发送自己的错误消息
除了来自
你会如何实现这一目标?有没有办法访问整个程序触发的完整错误序列?
谢谢
你不需要返回用
1 2 3 4 5 6 | try: # do stuff # FIXME: we should avoid catching too broad exception except Exception as err: # do stuff with exception raise err |
所以你的例子看起来像
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | 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() |
进一步改进
对于打印完整错误回溯,我们可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | 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() |
它只是冰山一角,
进一步阅读
- 记录HOWTO,
- SMTPHandler,用于通过SMTP发送电子邮件错误
您还可以创建一个
这是一个简单的例子,您可以修改它并将其实现到您的代码中,直到它满足您的需求:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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) |
输出:
1 | 'This is an Error!' |