第九课时之错误和异常

8.错误和异常

Python中至少有两种错误:语法错误和异常(syntax errorsexceptions)

 

8.1语法错误

 

语法错误也被称为解析错误,也许是你学习python过程中最常见抱怨:

语法分析器指出错误,并且在检测到错误的位置前面显示深红色。错误是由深红色前面的标记引起的。这个例子中函数print()被发现存在错误,因为它前面少了一个冒号(‘:’)

 

8.2异常

 

即使一条语句或表达式在语法上是正确的,当试图执行它时也可能引发错误。运行期检测到的错误称为异常,并且程序不会无条件的崩溃:很快,你将学到如何在python程序中处理他们。然而大多数异常都不会被程序处理,像这里展示的一样最终会产生一个错误信息:

错误信息的最后一行指出发生了什么错误。异常也有不同的类型。异常类型作为错误信息的一部分显示出来:示例中的异常分别为零除错误(ZeroDivisionError),命名错误(NameError)和类型错误(TypeError)。打印错误信息是异常的类型作为异常的内置名显示。对于所有的内置异常都是如此,不过用户自定义异常就不一定了。

 

错误信息的前半部分已堆栈的形式列出异常发生的位置。通常在堆栈中列出了源代码行,然而来自标准输入的源码不会显示出来

内置异常列出了内置异常和他们的含义。

 

8.3异常处理

 

通过编程处理选择的异常时可行的。看一下下面的例子:它会一直要求用户输入,直到输入一个合法的整数为止,但允许用户中断这个程序(使用Control-c或系统支持的任何方法)。注意:用户产生的中断会引发一个KeyboardInterrupt异常。

try语句按如下方式工作:

  • 首先执行try子句(tryexcept关键字之间的部分)
  • 如果没有异常发生,except子句在try语句执行完毕后就被忽略了
  • 如果在try子句执行过程中发生了异常,那么该子句其余的部分就会被忽略。如果异常匹配于except关键字后面指定的异常类型,就执行对应的except子句。然后继续执行try语句之后的代码。
  • 如果发生一个异常,在except自居中没有与之匹配的分支,他就会传递到上一级try语句中。如果最终仍找不到对应的处理语句,它就成为一个未处理异常,终止程序运行,显示提示信息。 

一个try语句可能包含多个except子句,分别指定处理不同的异常。至多只会有一个分支被执行。异常处理程序只会处理对应的try子句中发生的异常,在同一个try语句中,其他子句中发生的异常则不作处理。一个except子句可以在括号中列出多个异常的名字。例如:

最后一个except子句可以省略异常名称,以作为通配符使用。你需要慎用此法,因为它会轻易隐藏一个实际的程序错误!可以使用这种方法打印一条错误信息,然后重新抛出异常(允许调用者处理这个异常)

try...except语句可以带有一个else子句,该子句只能出现现在所有except子句之后。当try语句没有抛出异常时,需要执行一些代码,可以使用这个子句。例如:

使用else子句比在try子句中附加代码要好,因为这样可以避免try...except意外的截获本来不属于他们保护的那些代码抛出的异常。

发生异常时,可能会有一个附属值,作为异常的参数存在。这个参数是否存在,是什么类型,依赖于异常的类型。

在异常名(列表)之后,也可以为except子句指定一个变量。这个变量绑定于一个异常实例,它存储在instance.args的参数中。为了方便起见,异常实例定义了__str__(),这样就可以直接访问过打印参数而不必引用.args。这种做法不受鼓励。相反,更好的做法是给异常传递一个参数(如果要传递多个参数,可以传递一个元组),把它绑定到message属性一旦异常发生,它会在抛出前绑定所有指定的属性。

对于那些未处理的异常,如果一个他们带有参数,那么就会被作为异常信息的最后部分(‘详情’)打印出来。

异常处理器不仅仅处理那些在try子句中立刻发生的异常,也会处理那些try子句中调用的函数内部发生的异常。例如:

 

8.4抛出异常

 

raise语句允许程序员强制抛出一个指定的异常。例如:

想抛出的异常由raise的唯一参数标识。它必须是一个异常实例或异常类(继承自Exception的类)

如果你需要明确一个异常是否抛出,但不想处理它,raise语句可以让你很简单的重新抛出该异常:

 

8.5用户自定义异常

 

 在程序中可以通过创建新的异常类型来命名自己的异常(python类的内容请参见类)。异常通常应该直接或间接的从Exception类派生,例如:

 

 在这个例子中,Exception默认的__init__()被覆盖。新的方式简单的创建value属性。这就替换了原来创建args属性的方式。

 

 异常类中可以定义任何其他类中可以定义的东西,但是通常为了保持简单,只在其中加入几个属性信息,以供异常处理句柄提取。如果一个新创建的模块中需要抛出几种不同的错误时,一个通常的做法是为该模块定义一个异常基类,然后针对不同的错误类型派生出对应的异常子类:

 

8.5定义清理行为

 

try语句还有另一个可选的子句,目的在于定义在任何情况下都要一定要执行的功能。例如:

不管有没有发生异常,finally子句在程序离开try后都一定会被执行。当try语句中发生了未被except捕获的异常(或者他发生在exceptelse子句中),在finally子句执行完后它会被重新抛出。try语句经由breakcontinuereturn语句退出也一样会执行finally子句,以下是一个更复杂些的例子:

如你所见,finally子句在任何情况下都会执行。TypeError在两个字符串相除的时候抛出,未被except子句捕获,因此在finally子句执行完毕后重新抛出。

 

8.7预定义清理行为

 

有些对象定义了标准的清理行为,无论对象操作是否成功,不再需要该对象的时候就会起作用。以下示例尝试打开文件并把内容打印到屏幕上:

 

这段代码的问题在于代码执行完后没有立即关闭打开的文件。这在简单的脚本里没什么,但是大型应用程序就会出问题。With语句使得文件之类的对象可以确保总能及时准确地进行清理

 

语句执行后,文件f总会被关闭,即使是在处理文件中的数据时出错也一样。其他对象是否提供了预定义的清理行为要查看它们的文档。

 

posted @ 2018-02-09 15:37  LQ6H  阅读(172)  评论(0编辑  收藏  举报