【问题标题】:How to make python gracefully fail?如何让python优雅地失败?
【发布时间】:2009-01-31 01:22:08
【问题描述】:

我只是想知道如何让 python 在所有可能的错误中以用户定义的方式失败。

例如,我正在编写一个处理(大)项目列表的程序,其中一些项目可能不是我定义的格式。如果 python 检测到错误,它目前只是吐出一条丑陋的错误消息并停止整个过程。但是,我希望它只将错误与某些上下文一起输出到某个地方,然后继续进行下一项。

如果有人可以帮助我,将不胜感激!

非常感谢!

杰森

【问题讨论】:

    标签: python


    【解决方案1】:

    使用try... except成语

    try:
        # code that possibly breaks
    except RelevantError:          # you need to know what kind of errors you code might produce
        # show your message
    

    【讨论】:

    • 或者您可以捕获异常类型以捕获(几乎)所有错误异常。 (“几乎”是因为虽然错误类型应该从 Exception 派生,但这不是强制的。)
    • 我想这不是最佳实践
    • 是的,您应该捕获特定错误。请记住,请求宽恕比请求许可更好。所以更喜欢 try...except 而不是 if-you-can...else-error-message。
    【解决方案2】:

    以下是我在非常简单的脚本和中型应用程序中经常使用的一些基本策略。

    提示 1:在继续处理有意义的每个级别捕获错误。在您的情况下,它可能在循环内部。您不必保护每一行或每一个函数调用,而只需保护能够在错误中幸存下来的地方。

    提示 2:使用日志记录模块以一种可配置的方式报告发生的事情,该方式与您在大型应用程序中与其他模块的组合方式无关。开始在您的模块中导入根记录器,然后在几个不同的地方使用它,您最终可能会找出更合理的日志记录层次结构。

    import logging
    logger = logging.getLogger()
    
    for item in items:
        try:
            process(item)
        except Exception, exc:
            logger.warn("error while processing item: %s", exc)
    

    提示 3:定义“应用程序异常”,最终您可能希望定义此类异常的层次结构,但最好在需要时发现。当您处理的数据不是您所期望的或表明不一致的情况时,使用此类异常“冒泡”,同时将它们与由模型域之外的常规错误或问题(IO 错误)引起的正常标准异常区分开来等)。

    class DomainException(Exception):
        """Life is not what I expected"""
    
    def process(item):
        # There is no way that this item can be processed, so bail out quickly.
        # Here you are assuming that your caller will report this error but probably
        # it will be able to process the other items.
        if item.foo > item.bar:
            raise DomainException("bad news")
    
        # Everybody knows that every item has more that 10 wickets, so
        # the following instruction is assumed always being successful.
        # But even if luck is not on our side, our caller will be able to
        # cope with this situation and keep on working
        item.wickets[10] *= 2
    

    主要功能是最外面的检查点:最后在这里处理您的任务完成的可能方式。如果这不是一个 shell 脚本(但例如 UI 应用程序中对话框下的处理或 Web 应用程序中 POST 之后的操作),那么只有您报告错误的方式会发生变化(并且使用日志记录方法会完全分离实现从它的接口处理)。

    def main():
        try:
            do_all_the_processing()
            return 0
        except DomainException, exc:
            logger.error("I couldn't finish. The reason is: %s", exc)
            return 1
        except Exception, exc:
            logger.error("Unexpected error: %s - %s", exc.__class__.__name__, exc)
            # In this case you may want to forward a stacktrace to the developers via e-mail
            return 1
        except BaseException:
            logger.info("user stop") # this deals with a ctrl-c
            return 1
    
    if __name__ == '__main__':
        sys.exit(main())
    

    【讨论】:

    • 查看docs.python.org/library/logging.html#logging.debug 的日志模块文档 - 每个日志函数都有一个 exc_info 参数,用于告知是否记录回溯。您可以注册一个日志处理程序,以便在每个 logger.critical() 处向开发人员发送回溯。
    【解决方案3】:

    丑陋的错误消息意味着引发了异常。您需要捕获异常。

    一个好的起点是Python tutorial's section on exceptions.

    基本上,您需要将代码包装在 try...except 块中,如下所示:

    try:
        do_something_dangerous()
    except SomeException:
        handle_the_error()
    

    【讨论】:

      【解决方案4】:

      所有可能的错误

      其他答案几乎涵盖了如何让你的程序优雅地失败,但我想提一件事——你不想优雅地失败所有错误。如果您隐藏所有错误,则不会显示那些表明程序逻辑错误的错误 - 即您希望看到的错误。

      因此,尽管捕获异常很重要,但请确保您确切知道实际捕获了哪些异常。

      【讨论】:

        【解决方案5】:

        当 Python 遇到错误情况时,它会抛出异常。

        处理这个问题的方法是捕获异常并可能处理它。

        您可以查看有关 python tutorial 的异常部分。

        您表示有兴趣捕获所有异常。这可以通过捕获 Exception 类来完成。根据文档:

        所有内置,非系统退出 例外由此衍生 班级。所有用户定义的异常 也应该派生自这个类

        【讨论】:

          猜你喜欢
          • 2017-01-03
          • 2013-05-24
          • 1970-01-01
          • 1970-01-01
          • 2011-05-07
          • 1970-01-01
          • 2019-06-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多