Python 异常处理的实例详解
Python异常处理的实例详解
与许多面向对象语言一样,Python具有异常处理,通过使用try...except块来实现。
Note:Pythonvs.Java的异常处理
Python使用try...except来处理异常,使用raise来引发异常。Java和C++使用try...catch来处理异常,使用throw来引发异常。
异常在Python中无处不在;实际上在标准Python库中的每个模块都使用了它们,并且Python自已会在许多不同的情况下引发它们。在整本书中你已经再三看到它们了。
•使用不存在的字典关键字 将引发KeyError异常。
•搜索列表中不存在的值 将引发ValueError异常。
•调用不存在的方法 将引发AttributeError异常。
•引用不存在的变量 将引发NameError异常。
•未强制转换就混用数据类型 将引发TypeError异常。
在这些情况下,我们都在简单地使用PythonIDE:一个错误发生了,异常被打印出来(取决于你的IDE,可能会有意地以一种刺眼的红色形式表示),这便是。这叫做未处理异常;当异常被引发时,没有代码来明确地关注和处理它,所以异常被传给置在Python中的缺省的处理,它会输出一些调试信息并且终止运行。在IDE中,这不是什么大事,但是如果发生在你真正的Python程序运行的时候,整个程序将会终止。
然而,一个异常不一定会引起程序的完全崩溃。当异常引发时,可以被处理掉。有时候一个异常实际是因为代码中的bug(比如使用一个不存在的变量),但是许多时候,一个异常是可以预见的。如果你打开一个文件,它可能不存在。如果你连接一个数据库,它可能不可连接或没有访问所需的正确的安全证书。如果知道一行代码可能会引发异常,你应该使用一个try...except块来处理异常。
1.打开一个不存在的文件
>>>fsock=open("/notthere","r")(1) Traceback(innermostlast): File"",line1,in? IOError:[Errno2]Nosuchfileordirectory:'/notthere' >>>try: ...fsock=open("/notthere")(2) ...exceptIOError:(3) ...print"Thefiledoesnotexist,exitinggracefully" ...print"Thislinewillalwaysprint"(4) Thefiledoesnotexist,exitinggracefully Thislinewillalwaysprint
(1) 使用内置open函数,我们可以试着打开一个文件来读取(在下一节有关于open的更多内容)。但是那个文件不存在,所以这样就引发IOError异常。因为我们没有提供任何显式的对IOError异常的检查,Python仅仅打印出某个关于发生了什么的调试信息,然后终止。
(2) 我们试图打开同样不存在的文件,但是这次我们在一个try...except内来执行它。
(3) 当open方法引发IOError异常时,我们已经准备好处理它了。exceptIOError:行捕捉异常,接着执行我们自已的代码块,这个代码块在本例中只是打印出更令人愉快的错误信息。
(4) 一旦异常被处理了,处理通常在try...except块之后的第一行继续进行。注意这一行将总是打印出来,无论异常是否发生。如果在你的根目录下确实有一个叫notthere的文件,对open的调用将成功,except子句将忽略,并且最后一行仍将执行。
异常可能看上去不友好(毕竟,如果你不捕捉异常,整个程序将崩溃),但是考虑一下别的方法。你该不会希望获得一个指向不存在的文件的对象吧?不管怎么样你都得检查它的有效性,而且如果你忘记了,你的程序将会在下面某个地方给出奇怪的错误,这样你将不得不追溯到源程序。我确信你做过这种事;这可并不有趣。使用异常,一发生错误,你就可以在问题的源头通过标准的方法来处理它们。
2.为其他用途使用异常
除了处理实际的错误条件之外,对于异常还有许多其它的用处。在标准Python库中一个普通的用法就是试着导入一个模块,然后检查是否它能使用。导入一个并不存在的模块将引发一个ImportError异常。你可以使用这种方法来定义多级别的功能――依靠在运行时哪个模块是有效的,或支持多种平台(即平台特定代码被分离到不同的模块中)。你也能通过创建一个从内置的Exception类继承的类定义你自己的异常,然后使用raise命令引发你的异常。如果你对此感兴趣,请看进一步阅读的部分。
下面的例子演示了如何使用异常支持特定平台功能。代码来自getpass模块,一个从用户获得口令的封装模块。获得口令在UNIX、Windows和MacOS平台上的实现是不同的,但是这个代码封装了所有的不同之处。
#Bindthenamegetpasstotheappropriatefunction try: importtermios,TERMIOS(1) exceptImportError: try: importmsvcrt(2) exceptImportError: try: fromEasyDialogsimportAskPassword(3) exceptImportError: getpass=default_getpass(4) else:(5) getpass=AskPassword else: getpass=win_getpass else: getpass=unix_getpass
(1) termios是UNIX独有的一个模块,它提供了对于输入终端的底层控制。如果这个模块无效(因为它不在你的系统上,或你的系统不支持它),则导入失败,Python引发我们捕捉的ImportError异常。
(2) OK,我们没有termios,所以让我们试试msvcrt,它是Windows独有的一个模块,可以提供在MicrosoftVisualC++运行服务中的许多有用的函数的一个API。如果导入失败,Python会引发我们捕捉的ImportError异常。
(3) 如果前两个不能工作,我们试着从EasyDialogs导入一个函数,它是MacOS独有的一个模块,提供了各种各样类型的弹出对话框。再一次,如果导入失败,Python会引发一个我们捕捉的ImportError异常。
(4) 这些平台特定的模块没有一个有效(有可能,因为Python已经移植到了许多不同的平台上了),所以我们需要回头使用一个缺省口令输入函数(这个函数定义在getpass模块中的别的地方)。注意我们在这里所做的:我们将函数default_getpass赋给变量getpass。如果你读了官方getpass文档,它会告诉你getpass模块定义了一个getpass函数。它是这样做的:通过绑定getpass到正确的函数来适应你的平台。然后当你调用getpass函数时,你实际上调用了平台特定的函数,是这段代码已经为你设置好的。你不需要知道或关心你的代码正运行在何种平台上;只要调用getpass,则它总能正确处理。
(5) 一个try...except块可以有一条else子句,就像if语句。如果在try块中没有异常引发,然后else子句被执行。在本例中,那就意味着如果fromEasyDialogsimportAskPassword导入可工作,所以我们应该绑定getpass到AskPassword函数。其它每个try...except块有着相似的else子句,当我们发现一个import可用时,就绑定getpass到适合的函数。
如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!