首页 > 深入Python > 面向对象框架 > 处理异常 | << >> | ||||
diveintopython.org Python for experienced programmers |
象许多面向对象语言一样,Python具有异常处理,通过使用 try...except 块来实现。
Python使用 try...except 来处理异常,使用 raise 来引发异常。Java和C++使用 try...catch 来处理异常,使用 throw 来引发异常。 |
如果你已经了解了异常的全部知识,你可以跳过这节。如果你一直在一种松散语言下编程,或者你使用着真正的语言但没有用过异常,本节非常重要。
异常在Python中无处不在;实际上在标准Python库中的每个模块都使用了它们,并且Python自已会在许多不同的情况下引发它们。在整本书中你已经再三看到它们了。
在这些情况下,我们都在简单使用Python IDE:一个错误发生了,异常被打印出来(根据你的IDE,有意地以一种刺眼的红色形式表示),并且就这些。这叫做未处理异常;当异常被引发时,没有代码来显式地关注它和处理它,所以异常被传给置在Python中的缺省的处理,它会输出一些调试信息并且终止运行。在IDE中,这不是什么大事,但是如果发生在你真正的Python程序运行的时候,整个程序将会终止。[6]
然而,一个异常不一定会引起程序的完全崩溃。当异常引发时,可以被处理掉。有时候一个异常实际是因为代码中的bug(比如使用一个不存在的变量),但是许多时候,一个异常是可以预计的。如果知道一行代码可能会引发异常(象打开一个可能不存在的文件,或连到一个可能不能处理的数据库),你应该使用一个 try...except 块来处理异常。
>>> fsock = open("/notthere", "r") Traceback (innermost last): File "<interactive input>", line 1, in ? IOError: [Errno 2] No such file or directory: '/notthere' >>> try: ... fsock = open("/notthere") ... except IOError: ... print "The file does not exist, exiting gracefully" ... print "This line will always print" The file does not exist, exiting gracefully This line will always print
异常可能看不去不友好(毕竟,如果你不捕捉异常,整个程序将崩溃),但是考虑一下别的方法。你宁愿找回对于不存在文件的不可用的文件对象吗?不管怎么样你都得检查它的有效性,而且如果你忘记了,你的程序将会在下面某个地方给出奇怪的错误,这样你将不得不追溯到源程序。我确信你做过这种事;这可并不有趣。使用异常,一发生错误,你就可以在问题的源头通过标准的方法来处理它们。
除了处理实际的错误条件之外,对于异常还有许多其它的用处。在标准Python库中一个普通的用法就是试着导入一个模块,然后检查是否它能使用。导入一个并不存在的模块将引发一个 ImportError 异常。你可以使用这种方法来定义多级别的功能,依靠在运行时哪个模块是有效的,或支持多种平台(即平台特定代码被分离到不同的模块中)。
这个代码来源于 getpass 模块,一个从用户得到口令的封装模块。得到口令在UNIX,Windows,和MacOS平台上的实现是不同的,但是这个代码封装了所有不同。
# Bind the name getpass to the appropriate function try: import termios, TERMIOS except ImportError: try: import msvcrt except ImportError: try: from EasyDialogs import AskPassword except ImportError: getpass = default_getpass else: getpass = AskPassword else: getpass = win_getpass else: getpass = unix_getpass
termios 是一个UNIX特定模块,它提供了对于输入终端的底层控制。如果这个模块无效(因为它不在你的系统上,或你的系统不支持它),则导入失败,Python引发我们捕捉的 ImportError 异常。 |
|
哦,我们没有 termios,所以让我们试试 msvcrt,它是一个Windows特定模块,可以提供在Microsoft Visual C++运行服务中的许多有用的函数的一个API。如果导入失败,Python会引发我们捕捉的 ImportError 异常。 | |
如果前两个不能工作,我们试着从 EasyDialogs 导入一个函数,它是一个MacOS特定模块,提供了各种各样类型的弹出对话框。再一次,如果导入失败,Python会引发一个我们捕捉的 ImportError 异常。 | |
这些平台特定的模块没有一个有效(有可能,因为Python已经移植到了许多不同的平台上了),所以我们需要回头使用一个缺省口令输入函数(这个函数定义在 getpass 模块中的别的地方)。注意,我们在这里做的:我们将函数 default_getpass 赋给变量 getpass。如果你读了官方 getpass 文档,它会告诉你 getpass 模块定义了一个 getpass 函数。它是这样做的:通过绑定 getpass 到正确的函数来适应你的平台。然后当你调用 getpass 函数时,你实际上调用了平台特定的函数,是这段代码已经为你设置好的。你不需要知道或关心你的代码正运行在何种平台上;只要调用 getpass,则它总能正确处理。 | |
一个 try...except 块可以有一条 else 子句,就象 if 语句。如果在 try 块中没有异常引发,然后 else 子句被执行。在本例中,那就意味着如果 from EasyDialogs import AskPassword 导入可工作,所以我们应该绑定 getpass 到 AskPassword 函数。其它每个 try...except 块有着相似的 else 子句,当我们找到一个 import 可用时,来绑定 getpass 到适合的函数 。 |
进一步阅读
脚注
[6] 或者象某些信息所显示的,你的程序执行了一个非法动作。
私有函数 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
文件对象 |