本文共 3188 字,大约阅读时间需要 10 分钟。
程序如何处理意料之外的错误呢?异常为这个难题提供了解决方案。例如,如果在读取文件期间,计算机上的其他程序将其删除了,结果将如何呢?如果程序从网站下载网页时,该网站突然崩溃,结果又将如何呢?
在这些以及众多其他情形下,Python采取 措施是引发异常。异常是一种特殊的错误对象,你可以捕获并检查它们,以决定如何处理错误。
异常可能改变程序的控制流程。根据发生的时机,异常可能导致执行流程跳出函数或进入处理错误的代码块。
通常,你无法准确确碇哪一行可能引发异常,这带来了一些棘手的问题。因此,Python提供了一个特殊的异常处理结构,可用于捕获异常,并确保无论是否出现异常都将执行清理代码。
9.1 异常
一个异常的例子是IOError,当你试图打开不存在的文件时将引发这种异常:
出现异常后,如果不捕获或以任何其他方式进行处理,Python将立即停止运行程序 ,并显示
栈跟踪——异常发生前调用的函数清单。这对确定导致错误的代码行很有帮助。
在上述栈跟踪中,最后一行表明引发了IOError异常,具体地说,这意味着在当前工作目录中找不到文件unicorn.dat。IOError显示的错误消息随异常的原因而异。
引发异常
正如你从函数open身上看到的,Python内置函数和库函数通常在出现意外情况时引发异常。
例如,除以零将抛出异常:
在Python中,语法错误也会导致异常:
另外,在代码的任何地方都可使用raise语句故意引发异常,如下所示:
Python包含大量内置的异常,这些异常被组织成层次结构,更详细的信息请参阅Python文档。
9.2 捕获异常
异常发生时,你有如下两种选择。
1、忽略异常,让程序崩溃并显示栈跟踪。在开发程序期间,你通常想这样做,因为栈跟踪提供的调试信息很有帮助。
2、捕获异常,并打印友好的错误消息乃至试图修复问题。对于要供非程序员使用的程序,几乎都应这样做。普通用户可不想看到栈跟踪!
下面的示例演示了如何捕获异常。这里假设你要从用户那里获取一个整数,为此你反复提示用户,直到用户输入有效的整数:
#except.pydef get_age(): while True: try: n = int(input('How old are you? ')) return n except ValueError: print('Please enter an integer value.')
运行:
这个函数中的while循环是一个try/except块。你可将可能引发异常的代码放在try中。
只要try块中的代码出现异常,就将跳过其他所有示执行的语句,立即跳转到except块。在这个示例中,如果出现异常,将跳过return语句。
如果try块没有引发异常,将忽略(跳过)exceptValueError块。
在这个示例中,如果用户输入的字符串不是有效的整数,函数int()将引发异常ValueError,进而跳转到except ValueError块并打印错误消息。出现ValueError异常时,将跳过return语句——立即跳转到except块。
如果用户输入的是有效整数,就不会引发异常,因此Python将接着执行return语句,从而结束函数。
9.2.1 try/except块
try/except块的工作原理有点像if语句,但存在一个重大不同:if语句根据布尔表达式的结果决定如何做,而try/except块根据是否出现了异常决定如何做。
同一个函数可能引发多种异常,还可能出于不同原因引发相同的异常。下面是函数int()可能引发的3种异常
这表明int()至少会出于两个不同的原因引发异常ValueError,还至少出于另一个原因引发异常TypeError。
9.2.2 捕获多种异常
你可编写处理多种异常的try/except块。为此,可在except子句中指定多种异常:
#try_except.pydef convert_to_int1(s, base): try: return int(s, base) except(ValueError, TypeError): return 'error'
运行:
如果要分别处理不同的异常,可使用多个except子句:
#try_except2.pydef convert_to_int2(s, base): try: return int(s, base) except ValueError: return 'value error' except TypeError: return 'type error'
运行:
9.3.2 捕获所有异常
如果你在except子句中没有指定异常,它将捕获所有异常:
#try_except3.pydef convert_to_int3(s, base): try: return int(s, base) except: return 'except error'
运行:
这种except子句将捕获所有异常,它不关心发生的是哪种错误,而只关心是否发生了错误。在很多情况下,这就足够了。
9.3 清理操作
在try/except块中, 可包含执行清理操作的finally代码块,如下所示:
#except_invert.pydef invert(x): try: return 1/x except ZeroDivisionError: return 'ZeroDivisionError' finally: print('invert(%s) done' % x)
运行:
finally块肯定会执行,它要么在执行try块后执行,要么在执行except块后执行。在不管是否发生异常都要执行某些代码时,这很有用。例如,通常将关闭文件的语句放在finally块中,这样文件肯定会被关闭,即便发生了IOError异常。
with语句
为确保即便发生异常,也将尽早执行清理操作(如关闭文件),还可使用Python语句with。例如 ,请看下面的代码,它在屏幕上打印文件内容,并给每一行都加上行号:
#open_file.pydef open_file(fname): num = 1 f = open(fname) for line in f: print('%04d %s' % (num, line), end = '') num = num + 1
这里不知道文件对象f将在何时关闭。f通常在for循环结束后关闭,但不知道准确的时间。换句话说,不再需要后,f保持打开 状态多长时间是不确定的,如果其他程序试图访问这个文件,这可能是问题。
为确保不再需要的文件被尽早关闭,可使用with语句:
#with_open_file.pydef with_open_file(fname): num = 1 f = open(fname) for line in f: print('%04d %s' % (num, line), end = '') num = num + 1
这个代码片段的屏幕输出与前一个代码片段相同,但使用with语句时,将在for循环结束后立即执行文件对象清理操作(即关闭文件),避免了不再需要的f处于打开状态。
转载地址:http://uyiub.baihongyu.com/