python 中的异常处理

520 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第15天,点击查看活动详情


异常和断言

“例外”通常被定义为“不符合规范的东西”,因此有些罕见。在Python中,异常情况并不罕见。它们无处不在。几乎标准Python库中的每个模块都使用它们,Python本身在许多情况下都会引发它们。您已经看到了一些例外情况。

image.png

并且解释器将使用类似索引错误的内容进行响应:

image.png

索引错误是 Python 在程序尝试访问超出可索引类型边界的元素时引发的异常类型。索引错误后面的字符串提供了有关导致发生异常的原因的其他信息。

Python的大多数内置异常都处理程序试图执行没有适当语义的语句的情况。(我们将在本章后面讨论特殊异常 - 那些不处理错误的异常。

那些试图编写和运行Python程序的读者(我们希望你们所有人)已经遇到了很多这样的情况。最常见的异常类型包括类型错误、索引错误、名称错误和值错误。

处理异常

到目前为止,我们已将异常视为终端事件。当引发异常时,程序终止(在这种情况下,崩溃可能是一个更合适的词),我们回到我们的代码并试图找出出了什么问题。当引发导致程序终止的异常时,我们说已引发未处理的异常。

异常不一定会导致程序终止。引发异常时,可以并且应该由程序处理。有时,由于程序中存在错误(例如访问不存在的变量),因此会引发异常,但很多时候,异常是程序员可以并且应该预料到的。程序可能会尝试打开不存在的文件。如果交互式程序要求用户输入,则用户可能会输入不适当的内容。

Python提供了一个方便的机制,尝试例外,用于捕获和处理异常。一般形式是

image.png

如果您知道一行代码在执行时可能会引发异常,则应处理该异常。在编写良好的程序中,未处理的异常应该是异常。

image.png

打印(“成功/失败比率是”,success_failure_ratio)大多数情况下,此代码可以正常工作,但如果num_failures恰好为零,它将失败。尝试除以零将导致 Python 运行时系统引发零分割错误异常,并且永远不会到达 print 语句。

最好写一些类似的东西

image.png

进入 try 块后,解释器尝试计算表达式num_successes/num_failures。如果表达式计算成功,程序会将表达式的值赋给变量 success_failure_ratio,在 try 块的末尾执行 print 语句,然后继续执行 try-except 块后面的任何代码。但是,如果在表达式计算期间引发 ZeroDivisionError 异常,则控制将立即跳转到 except 块(跳过 try 块中的赋值和打印语句),执行 except 块中的 print 语句,然后执行继续执行该 try-except 块。

练习:实现符合以下规范的功能。使用“尝试例外”块。提示:在开始编码之前,您可能希望在 shell 中键入类似 1 + 'a' 的内容,以查看引发的异常类型。

image.png

如果程序代码块可能引发多种类型的异常,则保留字除外可以后跟一个异常元组,例如:

在这种情况下,如果在 try 块中引发任何列出的异常,则将输入 except 块。

image.png

如果在 try 块中引发任何类型的异常,则将输入 except 块。请考虑图 9-1 中的函数定义。

image.png

除了与 try 块关联的块之外,还有两个。如果在 try 块中引发异常,Python 首先检查它是否为零细分错误。如果是这样,它将附加一个特殊值,即浮点数与比率类型 nan。(值 nan 代表 “不是数字”。它没有文字,但可以通过将字符串“nan”或字符串“NaN”转换为类型浮点数来表示。当 nan 在浮点型表达式中用作操作数时,该表达式的值也是 nan。如果异常不是零细分错误,则代码将执行除块之外的第二个异常,这将引发具有关联字符串的 ValueError 异常。

原则上,永远不应输入除块之外的第二个块,因为调用get_ratios的代码应尊重get_ratios规范中的假设。然而,由于检查这些假设只会带来微不足道的计算负担,因此无论如何都可能值得练习防御性编程和检查。

下面的代码阐释了程序如何使用get_ratios。行中的名称消息(作为消息:的值错误除外)是绑定到引发时与值错误关联的参数(在本例中为字符串)。

image.png

执行后,它打印

image.png

为了进行比较,Figure_9-2 包含相同规范的实现,但没有使用 try-except。Figure_9-2 中的代码比 Figure_9-1 中的代码更长,更难阅读。它的效率也较低。(Figure_9-2 中的代码可以通过消除vectl_elem和vect2_elem的局部变量来缩短,但代价是通过反复索引到列表中来引入更多的低效率。

或者,我们可以为每种类型的异常编写一个单独的 except 块,它允许程序根据引发的异常选择操作。如果程序员写

image.png