我应该总是在`except`语句中指定一个异常类型吗?

Hor*_*Fat 86 python exception pep8

使用PyCharm IDE时,except:无异常类型的使用会触发IDE提醒此异常子句Too broad.

我应该忽略这个建议吗?或者是Pythonic总是具体的异常类型?

bab*_*unk 82

指定显式异常类型几乎总是更好.如果你使用一个裸except:子句,你最终可能会捕获除了你期望捕获的异常之外的异常 - 这可以隐藏错误或者当它们没有按照你期望的方式调试程序时更难.

例如,如果要在数据库中插入行,则可能需要捕获指示该行已存在的异常,以便您可以执行更新.

try:
    insert(connection, data)
except:
    update(connection, data)
Run Code Online (Sandbox Code Playgroud)

如果指定裸except:,则还会捕获套接字错误,指示数据库服务器已经崩溃.最好只捕获你知道如何处理的异常 - 程序通常在异常点失败而不是继续但是以奇怪的意外方式运行.

您可能想要使用裸设备的一种情况except:是您需要始终运行的程序的顶层,例如网络服务器.但是,你需要非常小心地记录异常,否则就不可能弄清楚出了什么问题.基本上,程序中最多只能有一个地方可以执行此操作.

其推论这一切是你的代码不应该这样做raise Exception('some message'),因为它迫使客户端代码使用except:(或except Exception:这是几乎一样糟糕).您应该定义一个特定于您想要发出的问题的异常(可能从某些内置的异常子类继承,如ValueErrorTypeError).或者你应该提出一个特定的内置异常.这使您的代码用户可以小心地捕获他们想要处理的异常.

  • +1非常正确.使用示例更有趣:`except:`还捕获(在许多其他事物中)`NameError`和`AttributeError`,所以如果你在`try`块中拼错了一些东西(例如你的"insert"函数实际上被称为`insert_one "因为有人不像他们应该那样重视一致性",所以它总是默默地试图"更新()". (7认同)
  • @delnan:比这更糟糕.`除了Exception:`也会捕获`NameError`和`AttributeError`.什么使得`除了:`这么糟糕的是它捕获了没有业务被捕获的东西,例如`SystemExit`(当你调用`exit`或`sys.exit`时引发,现在你已经阻止了预期的退出)和`KeyboardInterrupt`(再次,如果用户点击`Ctrl-C`,你可能不想继续运行只是为了惹他们).只有后者才能抓住真正的意义,应该明确地抓住它.至少`除了异常:`让这两个正常传播. (3认同)
  • 这是我一直不同意的一个 lint 建议。很多时候,无论抛出哪种异常,您都希望以相同的方式做出反应。我觉得这是早期 Java 中一些从未被放弃的具体建议的保留。 (3认同)
  • 那么,当您需要确保不会在当前调用站点上方抛出异常时该怎么办?即 - 我已经捕获了我可以预见会抛出的所有特定异常,现在我需要添加“如果我没有想到的这个东西被抛出,我需要在它杀死正在运行的执行上下文之前记录它”(例如```main()```)? (2认同)

ash*_*shr 36

你不应该忽视翻译给你的建议.

PEP-8样式指南Python:

捕获异常时,请尽可能提及特定异常,而不是使用bare except子句.

例如,使用:

 try:
     import platform_specific_module 
 except ImportError:
     platform_specific_module = None 
Run Code Online (Sandbox Code Playgroud)

一个裸的except:子句将捕获SystemExit和KeyboardInterrupt异常,使得用Control-C中断程序变得更加困难,并且可以掩盖其他问题.如果你想捕获所有发出程序错误信号的异常,请使用除Exception :(裸除了除了BaseException之外).

一个好的经验法则是将裸"除"子句的使用限制为两种情况:

如果异常处理程序将打印出来或记录回溯; 至少用户会意识到发生了错误.如果代码需要做一些清理工作,但随后让异常向上传播并加注.尝试...终于可以更好地处理这种情况.


Ton*_*son 9

这对Python没有特别的说明.

异常的全部意义在于尽可能地将问题处理到尽可能接近的地方.

因此,您可以保留在特殊情况下可能触发问题的代码以及彼此"下一步"的解决方案.

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

如果你把try catch放在那里,那么无论你的文件例程中有什么问题(只读,权限,UAC,不是真正的pdf等),每一个都会插入你的文件中找不到catch和你的用户是尖叫"但它在那里,这个代码是垃圾"

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

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

另一个你不关心它为什么出错了.例如打印.你可能有一个全面的问题,说你的打印机有问题,请整理出来,而不是因为它而杀死应用程序.如果您的代码使用某种计划执行一系列单独的任务,Ona类似的徒劳,您将不希望整个事情死亡,因为其中一个任务失败了.

注意如果您执行上述操作,我不能建议某种异常日志记录,例如try catch log end,足够高.

  • +1表示“您不在乎为什么会出错”。我在一行代码中的多个地方使用它,从URL解析日期/时间。第三方日期/时间解析库并未列出它可能抛出的所有异常(除了标准ValueError之外,我还发现了OverflowError和TypeError,但可能还有更多),无论如何,我真的不在乎为什么引发了异常,我只想向用户提供一条合理的错误消息,指出日期/时间出了点问题。 (2认同)

Pav*_*sov 5

始终指定异常类型,有很多类型您不想捕获,例如SyntaxErrorKeyboardInterruptMemoryError

  • @HorseloverFat:“ except Exception”捕获“ SyntaxError”和“ MemoryError”,因为它是它们的基类。`KeyboardInterrupt`、`SystemExit`(由 `sys.exit()` 引发)不会被捕获(它们是 BaseException 的直接子类) (4认同)
  • 使用 except Exception: 会避免我们不想捕获的上述类型吗? (2认同)