使用Python进行异常处理
- 来源 | 愿码(ChainDesk.CN)内容编辑
- 愿码Slogan | 连接每个程序员的故事
- 网站 | http://chaindesk.cn
- 愿码愿景 | 打造全学科IT系统免费课程,助力小白用户、初级工程师0成本免费系统学习、低成本进阶,帮助BAT一线资深工程师成长并利用自身优势创造睡后收入。
- 官方公众号 | 愿码 | 愿码服务号 | 区块链部落
- 免费加入愿码全思维工程师社群 | 任一公众号回复“愿码”两个字获取入群二维码
本文阅读时长:10min
本文所涉及知识点
- Python中有哪些异常 ?
- 使用try ... except子句控制程序流
- 通过处理异常来处理常见问题
- 创建和使用自定义异常类
在直接进入代码并解决这些问题之前,让我们首先了解异常是什么以及处理异常是什么意思。
什么是异常?
异常是Python中的对象。它为我们提供了有关在程序执行期间检测到的错误的信息。在调试应用程序时注意到的错误是未处理的异常,因为我们没有这些异常。在本文后面,您将学习处理这些异常的技巧。
在早期回溯中看到的ValueError和IndexError异常是Python中内置异常类型的示例 。在下一节中,您将了解Python支持的其他一些内置异常 。
最常见的异常
让我们快速回顾一些最常遇到的异常。最简单的方法是尝试运行一些错误的代码,让它报告错误回溯的问题!启动Python解释器并编写以下代码:
以下是一些异常情况:
正如您所看到的,代码的每一行都会抛出一个带有异常类型的错误回溯(突出显示)。这些是Python中的一些内置异常。Python提供BaseException作为所有内置异常的基类。但是,大多数内置异常不直接继承BaseException。相反,它们是从一个名为Exception的类派生而来的,而这个类又继承自BaseException。处理程序退出的内置异常(例如,SystemExit)直接从BaseException派生。您还可以创建自己的异常类作为Exception的子类。您将在本文后面了解到这一点。
异常处理
到目前为止,我们已经看到了异常的发生方式 现在,是时候学习如何使用try ... except子句来处理这些异常。以下伪代码显示了try ... except子句的一个非常简单的示例:
我们来看看前面的代码片段:
· 首先,程序尝试执行try子句中的代码。
· 在执行期间,如果出现错误(如果发生异常),它将跳出此try子句。try块中的其余代码不会被执行。
· 然后,它在except子句中查找适当的异常处理程序并执行它。
这里使用的 except子句是通用的。它将捕获try子句中发生的所有类型的异常。而不是拥有这个“全能”处理程序,更好的做法是捕获您预期的错误并编写特定于这些错误的异常处理代码。例如,try子句中的代码可能会抛出AssertionError。您可以编写特定的异常处理程序,而不是使用universal except子句,如下所示:
在这里,我们有一个except子句专门处理AssertionError。它还意味着除了AssertionError之外的任何错误都将作为未处理的异常漏掉。为此,我们需要使用不同的异常处理程序定义多个except子句。但是,在任何时候,只会调用一个异常处理程序。用一个例子可以更好地解释这一点。我们来看看下面的代码片段:
该试块调用solve_something() 。此函数接受一个数字作为用户输入,并断言该数字大于零。如果断言失败,它会直接跳转到处理程序,但AssertionError除外。
在另一个场景中,如果> 0,则执行solve_something()中的其余代码。您会注意到未定义变量x,这会导致NameError。此异常由另一个异常子句处理,但NameError除外。同样,您可以为预期的错误定义特定的异常处理程序。
提高并重新提出异常
Python中的raise关键字用于强制发生异常。换句话说,它引发了一个异常。语法很简单; 只需打开Python解释器并输入:
>>> raise AssertionError("some error message")
这会产生以下错误回溯:
Traceback (most recent call last): File "", line 1, in AssertionError : some error message
在某些情况下,我们需要重新引发异常。假设,在try子句中,您有一个将数字除以零的表达式。在普通算术中,这个表达没有意义。这是一个错误!这会导致程序引发一个名为ZeroDivisionError的异常。如果没有异常处理代码,程序将只打印错误消息并终止。
如果您希望将此错误写入某个日志文件然后终止该程序,该怎么办?在这里,您可以使用except子句首先记录错误。然后,使用不带任何参数的raise关键字来重新引发异常。异常将在堆栈中向上传播。在此示例中,它终止程序。可以使用raise关键字重新引发异常而不使用任何参数。
这是一个示例,显示如何重新引发异常:
可以看出,在解决a / b表达式时,会出现zeroexception的adivision。这是因为变量b的值设置为0。出于说明目的,我们假设此错误没有特定的异常处理程序。因此,我们将使用general except子句,在记录错误后重新引发异常。如果您想自己尝试,只需在新的Python文件中编写前面说明的代码,然后从终端窗口运行它。以下屏幕截图显示了上述代码的输出:
try ... except
可以在try ... except子句中指定可选的else块。在其他的只发生ifno异常块被执行的尝试......除了条款。语法如下:
在其他块的前执行最后条款,我们将在接下来的学习。
finally......clean it up!
还有其他东西可以添加到try ...除了... else story:一个可选的finally子句。顾名思义,此子句中的代码在关联的try ... except块的末尾执行。无论是否引发异常,finally子句(如果指定)将在try ... except子句的末尾执行。想象一下它是由Python提供的全天候保证!以下代码段显示了finally块的运行情况:
运行这个简单的代码将产生以下输出:
$ python finally_example1.py Enter a number: -1 Uh oh..Assertion Error. Do some special cleanup
输出中的最后一行是finally子句中的print语句。
带有和不带finally子句的代码片段如下面的屏幕截图所示。即使except子句指示代码从函数返回,也确保finally子句中的代码最终执行。
在最后条款通常用于离开功能之前执行清理任务。示例用例是关闭数据库连接或文件。但请注意,为此,您还可以在Python中使用with语句。
编写一个新的异常类
创建一个从Exception派生的新异常类是微不足道的。打开Python解释器并创建以下类:
>>> class GameUnitError(Exception): ... pass ... >>>
就这样!我们有一个新的异常类GameUnitError,可以部署了。如何测试此异常?在Python解释器中键入以下代码行:
>>> raise GameUnitError("ERROR: some problem with game unit")
引发新创建的异常将打印以下回溯:
>>> raise GameUnitError("ERROR: some problem with game unit") Traceback (most recent call last): File "", line 1, in __main__.GameUnitError: ERROR: some problem with game unit
将GameUnitError类复制到其自己的模块gameuniterror.py中,并将其保存在与attackoftheorcs_v1_1.py相同的目录中。
接下来,更新attackoftheorcs_v1_1.py文件以包含以下更改:
首先,在文件的开头添加以下import语句:
from gameuniterror import GameUnitError
第二个变化是在AbstractGameUnit.heal方法中。更新后的代码显示在以下代码段中。观察高亮代码,只要提出的价值自定义异常self.health_meter超过的self.max_hp。
通过这两个更改,运行之前创建的heal_exception_example.py。您将看到引发新的异常,如以下屏幕截图所示:
扩展异常类
我们可以用GameUnitError类做更多的事情吗?当然!就像任何其他类一样,我们可以定义属性并使用它们。让我们进一步扩展这个课程。在修改后的版本中,它将接受一个额外的参数和一些预定义的错误代码。更新的GameUnitError类显示在以下屏幕截图中:
我们来看看前面屏幕截图中的代码:
· 首先,它调用Exception超类的__init__方法,然后定义一些额外的实例变量。
· 一个新的dictionary对象self。error_dict将错误整数代码和错误信息保存为键值对。
· 该self.error_message存储有关根据提供的错误代码当前错误的信息。
· 在尝试......除了子句确保error_dict实际上已经由指定的键码的说法。它不在except子句中,我们只是检索默认错误代码为000的值。
到目前为止,我们已经对GameUnitError类和AbstractGameUnit.heal方法进行了更改。我们还没有完成。拼图的最后一块是修改主要在程序heal_exception_example.py文件。代码显示在以下屏幕截图中:
我们来看看代码:
· 由于heal_by值太大,try子句中的heal方法会引发GameUnitError异常。
· new except子句处理GameUnitError异常,就像任何其他内置异常一样。
· 在except子句中,我们有两个print语句。第一个打印health_meter> max_hp!(回想一下,当在heal方法中引发此异常时,此字符串被作为GameUnitError实例的第一个参数给出)。第二个print语句检索并打印GameUnitError实例的error_message属性。
我们已经做好了所有的改变。我们可以在终端窗口中运行此示例:
$ python heal_exception_example.py
该程序的输出显示在以下屏幕截图中:
在这个简单的例子中,将错误信息打印到控制台。您可以进一步将详细错误日志写入文件,并跟踪应用程序运行时生成的所有错误消息。