错误和异常
Learn from python2.7 official documentation
学习至此,曾遇到过的错误信息(error messages)有两种:语法错误(syntax errors)和异常(exceptions)。
8.1 语法错误Syntax Error
语法错误又称为解析错误(parsing errors),语句或表达式在语法上出错时,会引发这种错误。
在错误信息中,出现输入错误的脚本文件名和错误位置的行号将被打印出来,并提示错误信息:SyntaxError: invalid syntax
。
8.2 异常Exception
即使语法正确,仍在执行时检测到的错误,被称为异常。
大多数的异常并不会被程序处理,而是显示错误信息:
1 | 10 * (1/0) |
异常的错误信息前部分,同样会提示出现输入错误的脚本文件名和错误位置的行号,这部分通常以出现异常源代码行的堆栈回溯清单(stack traceback listing)的形式,显示出发生异常时的上下文。
错误信息的最后一行,会打印出异常类型的名称和此异常的详细描述信息。作为异常类型打印的字符串是发生的内置异常(built-in exception)的名称,对于用户定义异常(user-defined exception)则不一定如此,标准的异常类型是内置的标识符(built-in identifier)而不是保留的关键字(reserved keyword)。
8.3 处理Handling异常
8.3.1 try语句
1 | while True: |
try
语句工作原理:
首先,执行
try
子句(try
和except
关键字之间的多行语句);如果没有出现异常,跳过
except
子句并完成try
语句的执行;如果出现异常,则跳过
try
子句中剩下的部分,如果异常的类型和except
关键字后面的异常类型匹配,则执行except
子句,然后完成try
语句的执行,继续之后的代码;如果异常类型和
except
子句中指定的不匹配,则将传递到外部的try
语句中处理(我理解为嵌套),如果没有找到处理器,则将其判定为未处理异常(unhandled exception),并终止执行,返回异常信息。
8.3.2 except子句
一个try
语句可以有多个except
子句,用于为try
子句中可能发生的不同异常分别指定处理程序,每次执行至多执行一个处理程序。
except
子句可以将多个异常命名为带括号的元组:
1 | except (RuntimeError, TypeError, NameError): |
最后的except
子句可以省略异常名,以用作通配符(wildcard)。此方法可以用于打印错误消息,然后重新引发异常(使用raise
语句,令程序自行引发异常):
1 | except: |
8.3.3 else子句
try
语句中,可以选择在所有的except
子句后面,添加else
子句,来写入try
子句不引发异常时必须执行的代码:
1 | for arg in sys.argv[1:]: |
8.3.4 finally子句:定义清理操作Clean-up Action
try
语句中,可以在所有的子句后面加入finally
子句,finally
子句一定会在try
语句退出前执行,无论try
子句中是否触发异常
1 | def divide(x, y): |
在实际应用程序中,finally
子句用于定义必须在所有情况下执行的清理操作,尤其对于释放外部资源(如文件、网络连接)十分有用。
8.3.5 异常参数exception’s argument
当一个异常发生时,它所具有的相关信息(associated value)称为异常参数,参数的存在与否及其类型,取决于异常类型。异常参数一般作为未处理异常中错误信息的最后一部分打印出来。
except
子句可以在异常名后,使用as
关键字来指定一个变量,该变量与包含instance.args
中存储的异常参数的异常实例(exception instance)绑定,由于异常实例定义了__str()__
,所以异常参数可以通过此变量直接打印,而不必引用.args
:
1 | try: |
8.4 抛出Raising异常
raise
语句可以用来强制引发指定的异常:
1 | raise NameError('HiThere') |
raise
语句的唯一参数表示要引发的异常,这个参数必须是一个异常实例或异常类(由Exception
派生的类)。
8.5 用户自定义User-defined异常
可以通过创建一个新的异常类,来为自定义异常命名,异常类必须直接或间接地继承Exception
类:
1 | class MyError(Exception): |
在这个例子中,Exception
默认的__init()__
方法被重写,新的方法只是简单的创建类中的一个value
属性,这将替代原方法中创建args
属性的默认行为:
1 | try: |
大多数异常都定义为名称以"Error"
结尾,类似于标准异常的命名。
8.7 with语句&预定义的Predefined清理操作
某些对象定义了在不再需要该对象时要执行的标准清理操作,无论使用该对象的操作是成功还是失败。with
语句允许这样的对象总是保证被即使清理:
1 | with open("myfile.txt") as f: |
在执行语句之后,File
对象f
总是关闭的,即使在执行过程中遇到了问题。