【问题标题】:Should I always specify an exception type in `except` statements?我应该总是在 `except` 语句中指定异常类型吗?
【发布时间】:2013-01-25 16:23:40
【问题描述】:

在使用 PyCharm IDE 时,如果使用不带异常类型的 except: 会触发 IDE 提醒该异常子句是 Too broad

我应该忽略这个建议吗?还是 Pythonic 总是指定异常类型?

【问题讨论】:

  • 如果你想了解更多关于这个的信息而不是答案,谷歌吞咽异常。您可以在它们旁边进行各种其他有趣的注意事项。代码异味是另一种。

标签: python exception pep8


【解决方案1】:

试试这个:

try:
    #code
except ValueError:
    pass

我从这个链接得到了答案,如果其他人遇到这个问题Check it out

【讨论】:

    【解决方案2】:

    这里是我使用的地方,除了没有类型

    1. 快速而肮脏的原型设计

    这是我的代码中未检查异常的主要用途

    1. 顶级 main() 函数,我在其中记录每个未捕获的异常

    我总是添加这个,这样生产代码就不会溢出堆栈跟踪

    1. 应用层之间

    我有两种方法:

    • 第一种方法:当较高层调用较低层函数时,它将调用包装在类型化异常中以处理“顶级”较低层异常。但是我添加了一个通用的 except 语句,以检测低级函数中未处理的低级异常。

    我更喜欢这种方式,我发现更容易检测到哪些异常应该被适当地捕获:当较低级别的异常被更高级别记录时,我可以更好地“看到”问题 p>

    • 第二种方法:较低层的每个顶级函数都将其代码包装在一个通用的异常中,以捕获该特定层上所有未处理的异常。

    一些同事更喜欢这种方式,因为它可以在他们“所属”的低级函数中保留低级异常。

    【讨论】:

      【解决方案3】:

      指定明确的异常类型几乎总是更好。如果您使用裸露的except: 子句,您最终可能会捕获到您希望捕获的异常之外的异常 - 这可能会隐藏错误,或者在程序没有按照您的预期运行时使调试变得更加困难。

      例如,如果您要向数据库中插入一行,您可能希望捕获一个表明该行已存在的异常,以便进行更新。

      try:
          insert(connection, data)
      except:
          update(connection, data)
      

      如果您指定一个空的except:,您还会捕获一个套接字错误,表明数据库服务器已经崩溃。最好只捕获您知道如何处理的异常 - 程序在异常点失败通常比继续但以奇怪的意外方式表现更好。

      您可能想要使用裸except: 的一种情况是您需要始终运行的程序的顶层,例如网络服务器。但是,您需要非常小心地记录异常,否则将无法找出问题所在。基本上,一个程序中最多应该只有一个地方可以做到这一点。

      所有这一切的一个必然结果是您的代码永远不应该使用raise Exception('some message'),因为它会强制客户端代码使用except:(或except Exception:,这几乎一样糟糕)。您应该定义一个特定于您要发出信号的问题的异常(可能继承自一些内置异常子类,如ValueErrorTypeError)。或者你应该提出一个特定的内置异常。这使您的代码的用户能够小心地捕获他们想要处理的异常。

      【讨论】:

      • +1 非常正确。这个例子更有趣:except: 还捕获(以及许多其他内容)NameErrorAttributeError,所以如果您在 try 块中拼错了某些内容(例如,您的“插入”函数实际上称为 insert_one因为有人没有像他们应该的那样重视一致性),它总是默默地尝试update()
      • 那么当您需要确保不会在当前调用站点上方抛出异常时怎么办?即 - 我已经捕获了我可以预见的所有特定异常被抛出,现在我需要添加“如果我没有想到的这个东西被抛出,我需要在它杀死正在运行的执行上下文之前记录它”(例如main())?
      • 这就是我在“一个案例......”开头的段落中所说的那种情况。有时确实需要它,但任何给定的程序实际上应该只有一个地方可以做到这一点。并且您需要注意它在日志中清楚地表明正在发生的事情,否则您将有一段令人沮丧的时间试图找出您的程序为什么没有正确处理事件/请求/任何事情。
      • @delnan:比这更糟糕。 except Exception: 也会捕获 NameErrorAttributeError。是什么让裸except: 如此糟糕的是它捕捉到了没有被捕捉到的东西,例如。 SystemExit(当你调用exitsys.exit时引发,现在你已经阻止了预期的退出)和KeyboardInterrupt(同样,如果用户点击Ctrl-C,你可能不想继续运行只是为了惹恼他们)。只有后者才是真正有意义的捕捉,它应该被明确捕捉。至少except Exception: 让这两个正常传播。
      • 这是我一直不同意的一个 lint 建议。很多时候,无论抛出什么样的异常,您都希望以相同的方式做出反应。我觉得这是对早期 Java 的一些具体建议的保留,从未放弃过。
      【解决方案4】:

      您不应忽视口译员给您的建议。

      来自PEP-8 Python 风格指南:

      在捕获异常时,只要提及特定的异常 可以代替使用裸的 except: 子句。

      例如,使用:

       try:
           import platform_specific_module 
       except ImportError:
           platform_specific_module = None 
      

      一个简单的 except: 子句将捕获 SystemExit 和 KeyboardInterrupt 异常,使其更难 使用 Control-C 中断程序,并且可以掩饰其他问题。 如果要捕获所有表明程序错误的异常,请使用 except Exception:(裸的 except 等价于 except BaseException:)。

      一个好的经验法则是将裸“除外”子句的使用限制为两个 案例:

      如果异常处理程序将打印或记录 追溯;至少用户会意识到发生了错误。 如果代码需要做一些清理工作,然后让异常 随着 raise 向上传播。尝试...终于可以成为更好的方法 处理这个案子。

      【解决方案5】:

      这不是 Python 特有的。

      例外的全部意义在于尽可能接近问题的原因来处理问题。

      因此,您保留在特殊情况下可能触发问题的代码和解决方案“相邻”。

      问题是您无法知道一段代码可能引发的所有异常。你所能知道的是,如果它是一个说找不到文件的异常,那么你可以捕获它并提示用户获取一个执行或取消该功能。

      如果你把 try catch 放在那个周围,那么无论你的文件例程中有什么问题(只读、权限、UAC、不是真正的 pdf 等),每个人都会进入你的文件 not found catch,你的用户在尖叫“但它就在那里,这段代码是垃圾”

      现在有几种情况你可能会抓住一切,但应该有意识地选择它们。

      它们是捕获,撤消一些本地操作(例如创建或锁定资源,(例如打开磁盘上的文件进行写入),然后再次抛出异常,以供更高级别处理)

      另一个你不在乎为什么会出错。以印刷为例。你可能有一个问题,说你的打印机有问题,请解决它,不要因为它而杀死应用程序。如果您的代码使用某种时间表执行一系列单独的任务,那么类似的徒劳无功,您不会希望整个事情都死掉,因为其中一个任务失败了。

      注意如果您执行上述操作,我不能推荐某种异常日志记录,例如尝试捕获日志结束,足够高。

      【讨论】:

      • 我会说这是关于平衡。您必须足够早地捕获异常以便能够从中恢复,并且必须足够晚才能知道如何处理它。这就是为什么 Java 异常处理会造成如此严重的破坏,因为您必须在每一步都重新包装异常并且您会丢失信息。
      • +1 表示“你不在乎为什么会出错”。我在围绕一行代码的几个地方使用它,我从 URL 解析日期/时间。第三方日期/时间解析库没有列出它可以抛出的所有异常(除了标准的 ValueError 之外,我还发现了 OverflowError 和 TypeError,但可能还有更多),反正我真的不在乎为什么抛出异常,我只想向用户提供合理的错误消息,说明日期/时间有问题。
      【解决方案6】:

      总是指定异常类型,有很多类型你不想捕获,比如SyntaxErrorKeyboardInterruptMemoryError等。

      【讨论】:

      • 会使用except Exception: 避免上述我们不想捕获的类型吗?
      • except Exception 很好。
      • @HorseloverFat: except Exception 捕获 SyntaxErrorMemoryError 因为它是它们的基类。 KeyboardInterruptSystemExit(由sys.exit() 引发)未被捕获(它们是直接的 BaseException 子类)
      • 听起来不太理想 - 最好更精确地指定。
      【解决方案7】:

      您还将捕捉到例如使用 Control-C,所以除非你再次“抛出”它,否则不要这样做。但是,在这种情况下,您应该使用“finally”。

      【讨论】:

        猜你喜欢
        • 2014-06-24
        • 1970-01-01
        • 2019-12-31
        • 2014-08-10
        • 1970-01-01
        • 2014-08-07
        • 1970-01-01
        • 1970-01-01
        • 2020-07-06
        相关资源
        最近更新 更多