直到现在错误消息还没有被提起,但是如果你尝试了示例的话你可能已经看到一些。这是(至少)两种可区别的错误,语法错误和异常。
8.1 语法错误
语法错误,也被称为解析错误,也许是你得到的最普通类型的抱怨当你仍然在学习Python的时候:
解析器重复错误行,并在本行最先检测到错误的地方显示一个小箭头。错误是由箭头前面的标记引起的。示例中错误在函数print()处被检测出来,因为它前面少了一个冒号。文件名称和行号被打印出来,所以你知道应该去输入脚本的哪个地方寻找情况。
8.2 异常
即使一个语句或表达式在语法上是正确的,在尝试运行它时也可能引发一个错误。在运行期被检测到的错误称为异常,并不是无条件致命的,稍后你会学习如何在Python程序中处理它们。许多异常没有被程序处理,然而,会导致下面的错误消息:
错误消息的最后一行指示发生了什么。异常有不同的类型,类型作为消息的一部分被打印出来,示例中的类型是 除零错误,名称错误和类型错误。作为异常类型被打印的字符串是发生的内建异常的名字。对于所有的内建异常这都是真的,但是对于用户定义的异常不一定是真的。标准的异常名称是内建的标识符(不是保留关键字)。
本行其余的内容提供了基于异常的类型和是什么引发它的详细信息。
错误消息的前面部分显示了异常发生位置的上下文,以堆栈跟踪的形式。一般情况下,它包含列出源文件行的堆栈跟踪,它将不显示从标准输入读到的行。
8.3 处理异常
可以写程序来处理选定的异常。看下面的示例,要求用户输,直到一个合法的整数被键入,但是允许用户中断程序,一个用户产生的中断被用信号发送通过引发一个异常:
try语句按如下方式工作
- 首先,try从句(在关键字try和except之间的语句)被执行。
- 如果没有异常发生,except从句被跳过,try语句执行完毕。
- 如果在执行try语句的时候有异常发生,剩余的语句会被跳过。如果它的类型和except后面的命名异常相匹配,这个except从句被执行,然后在try语句后面继续执行。
- 如果有异常发生,并且它和except从句中的命名异常类型不匹配,它被传递到外层的try语句,如果没有发现处理程序,它就是一个未处理的异常,程序停止执行,显示上面的错误信息。
一个try语句或许有多个except从句,来为不同的异常指定处理程序。至多一个处理程序将被执行。处理程序只处理发生在相应try从句中的异常,而不处理发生在同一个try语句的其它处理程序中的异常。一个except从句可以命名多个异常,使用一个括号元组,例如:
最后一个except从句或许可以忽略异常的名字,作为通配符。这样使用应该极其谨慎,因为这样容易掩饰掉一个真正的编程错误。它也可以被用来打印一个错误信息,然后重新引发这个异常(也允许调用者来处理这个异常):
try...except语句有一个可选的else从句,如果有的话必须跟在所有的except从句后面。对于那些异常没有发生时必须执行的代码非常有用。例如:
else从句的使用比往try从句里添加额外的代码要好,因为它避免了意外的捕获一个异常,并不是被try...except语句保护的代码所引起的。
当一个异常发生时,它或许有一个关联的值,也被称为异常的参数。这个参数的出现和类型取决与异常的类型。
except从句可以在异常名称后面指定一个变量。这个变量绑定到一个异常实例,并且参数被存储在instance.args里。为了方便,异常实例定义了__str__()函数,所以参数可以被直接的打印出来而不用引用.args。你可以在引发前首先实例化一个异常,并且添加任何渴望的属性:
如果一个异常有参数,对于未处理的异常,它们作为信息的最后部分被打印出来。
异常处理程序并不仅仅处理那些在try从句中直接发生的异常,同样也处理那些在try从句中调用(或间接调用)的函数里面发生的异常。例如:
8.4 引发异常
raise语句允许程序员迫使一个指定的异常发生。例如:
raise的惟一参数指示被引发的异常。它要么是一个异常实例或是一个异常类。
如果你需要决定一个异常是否被引发,但是不打算处理它,一个更简单的raise语句形式允许你再次引发异常:
8.5 用户定义异常
通过创建一个新的异常类,程序可以命名它们自己的异常。异常应该典型的继承于Exception类,要么直接的或间接地。例如:
在这个示例里面,Exception的默认的__init__()已经被重写。新的行为简单的创建一个value属性。这替换了创建args属性的默认行为。
异常类可以被定义做任何其它类可以做的事情,但是通常保持简单,通常只提供一些属性,允许有关错误的信息被异常的处理程序抽取到。当创建一个能引发几个不同错误的模块时,一个通用的实践是为那个模块里定义的所有异常创建一个基类,对于不同的错误情况,创建特定的异常子类:
许多异常被定义为以Error结尾的名称,与标准异常的命名相似。
许多标准的模块定义它们自己的异常来报告可能发生在它们定义的函数里面的错误。
8.6 定义清除动作
try语句有一个可选的从句,它的目的是定义在任何情况下都必须被执行的清除动作。例如:
一个finally从句在离开try语句之前总是被执行,无论一个异常发生与否。当try从句里面发生了一个异常,并且没有被一个except从句处理(或异常发生在except从句或else从句),它会在finally从句被执行后重新引发。当try语句的任何从句通过break,continue或return语句离开时,finally从句也会被执行。一个更复杂的示例:
就像你看到的那样,finally从句在任何情况下都会被执行。通过两个字符串相除而引发的TypeError没有被except从句处理,所以在finally从句被执行后重新引发。
在现实世界的应用程序里,finally从句对于释放外部资源非常有用(像文件和网络连接),不管对资源的使用是否成功。
8.7 预定义的清除动作
一些对象定义标准的清除动作来保证当对象不再被需要,不管使用对象的操作是成功或是失败。看下面的示例,尝试打开一个文件并把它的内容打印到屏幕:
这个代码的问题是在这部分代码执行完后,文件的打开状态持续一个不确定的时间。在简单的脚本里面这不算是一个问题,但对于大的应用来说是一个问题。with语句允许像文件这样的对象以确保它们总是被合适的和正确的被清除的方式来使用:
在语句执行后,文件f总是被关闭,即使在处理行时遇到了问题。像文件这样的,提供了预定义清除动作的对象在文档里将指出这一点。
本文是对官方网站内容的翻译,原文地址:http://docs.python.org/3/tutorial/errors.html |