无聊之人--除了技术,还是技术,你懂得
分类: Python/Ruby
2011-08-09 16:48:00
Chapter 6. Exceptions and File Handling
In this chapter, you will dive into exceptions, file objects, for loops, and the os and sys modules. If you've used exceptions in another programming language, you can skim the first section to get a sense of Python's syntax. Be sure to tune in again for file handling.
在本章你将研究异常,文件对象,for循环以及os&sys模块。如果你在其它程序语言中使用过异常,你可以掠过第一个部分来来得到Python语法的一个感性认识。对文件处理也是同样。
6.1. Handling Exceptions
6.1 异常处理
Like many other programming languages, Python has exception handling via try...except blocks.
同其它大多数可编程语言一样,Python通过使用try…exception来处理异常。
|
|
|
Python uses try...except to handle exceptions and raise to generate them. Java and C++ use try...catch to handle exceptions, and throw to generate them. Python使用try…exception来处理异常并抛出它们。Java和C++使用try..catch来处理一程并抛出异常。 |
|
Exceptions are everywhere in Python. Virtually every module in the standard Python library uses them, and Python itself will raise them in a lot of different circumstances. You've already seen them repeatedly throughout this book.
Python中异常无处不在。实际上Python标准类库中每一个模块都在使用异常,并且Python本身在不同的环境下也抛出不同的异常。在本书中你早已经多次见过它们。
In each of these cases, you were simply playing around in the Python IDE: an error occurred, the exception was printed (depending on your IDE, perhaps in an intentionally jarring shade of red), and that was that. This is called an unhandled exception. When the exception was raised, there was no code to explicitly notice it and deal with it, so it bubbled its way back to the default behavior built in to Python, which is to spit out some debugging information and give up. In the IDE, that's no big deal, but if that happened while your actual Python program was running, the entire program would come to a screeching halt.
这上面的这些例子中,你是在PythonIDE简单使用python:一个错误发生,异常然后被打印出来(依赖你所使用的IDE,或许使用显眼的红色来标示出来),这就是异常。这是未处理的异常,当异常被抛出的时候,并不存在显示的代码来处理异常,因此异常按原路进行冒泡到Python中默认的行为,也就是打印出来一些调试信息并退出。在IDE中,这不是什么大的事情,但是它发生了当你实际Python程序在运行的时候,整个程序将会戛然而止。
An exception doesn't need result in a complete program crash, though. Exceptions, when raised, can be handled. Sometimes an exception is really because you have a bug in your code (like accessing a variable that doesn't exist), but many times, an exception is something you can anticipate. If you're opening a file, it might not exist. If you're connecting to a database, it might be unavailable, or you might not have the correct security credentials to access it. If you know a line of code may raise an exception, you should handle the exception using a try...except block.
对于通过异常崩溃的程序一个异常不必产生结果。异常,当被抛出的时候,可以被捕捉。有时一个异常是确实真实存在的,这是因为在你的代码中存在错误(比如访问不存在的变量),但是更多的情况下,异常是你可以预测的事情。如果你正在打开一个文件,文件或许不存在。如果你在挂接数据库,数据库可能不可用,或许你没有 正确的安全凭据来放完它。如果你知道某行代码可能抛出异常,那你就应该使用try…exception来捕捉该异常
Example 6.1. Opening a Non-Existent File
例5.1打开一个不存在的文件
Using the
built-in open function, you can try to open a file for reading
(more on open in the next section). But the file doesn't exist, so
this raises the IOError exception. Since you haven't provided any
explicit check for an IOError exception, Python just
prints out some debugging information about what happened and then gives up. 使用内置的open函数,你可以尝试打开一个只读文件(更多的文件打开操作在下一节介绍)。但是文件不存在,因此抛出了IOError异常。既然你没有对IOError提供异常的检测,Python就简单的打印出一些调试信息即发生了什么事情然后程序就终止掉了。 You're trying to open the same
non-existent file, but this time you're doing it within
a try...except block. 你尝试打开相同的并不存在的文件,但是这次你在一个try…block代码块中处理。 When the open method raises
an IOError exception, you're ready for it. The except
IOError: line catches the exception and executes your own block of code,
which in this case just prints a more pleasant error message. 当open方法抛出IOError异常的时候,你正在准备处理它。IOError异常行捕捉道了异常并执行了一想要的执行的代码块,在本例中就是简单的打印出一个让人高兴错误消息。 Once an exception has been handled,
processing continues normally on the first line after
the try...except block. Note that this line will always print,
whether or not an exception occurs. If you really did have a file
called notthere in your root directory, the call
to open would succeed, the except clause would be ignored,
and this line would still be executed. 一旦一个异常被处理,程序就会在try..catch代码块后第一行代码处正常继续下去。请注意这行代码总会打印,不论异常是否发生。如果你确实有一个文件为notthere在你的根目录下,对文件的调用将会成功进行,异常语句将被忽略掉,这行仍然被执行。
Exceptions may seem unfriendly (after all, if you don't catch the exception, your entire program will crash), but consider the alternative. Would you rather get back an unusable file object to a non-existent file? You'd need to check its validity somehow anyway, and if you forgot, somewhere down the line, your program would give you strange errors somewhere down the line that you would need to trace back to the source. I'm sure you've experienced this, and you know it's not fun. With exceptions, errors occur immediately, and you can handle them in a standard way at the source of the problem.
异常看起来不死太友好(毕竟,如果你捕捉的话,你的整个程序将会崩溃),但是异常是可选的。你是否愿意使用一个文件对象来访问一个不存在的文件?你必须一某种方式来校验它的合法性,如果你忘记了,在这行代码后面某处,你的程序会给你某些奇怪的提示,你应该回溯到源代码出。我敢肯定的说你肯定经历这中情况。你知道这样很无聊。通过异常,错误紧接着发生,然后你就可以使用一种标准的方式在源代码处来处理它。
6.1.1. Using Exceptions For Other Purposes
异常存在的其它目的
There are a lot of other uses for exceptions besides handling actual error conditions. A common use in the standard Python library is to try to import a module, and then check whether it worked. Importing a module that does not exist will raise an ImportError exception. You can use this to define multiple levels of functionality based on which modules are available at run-time, or to support multiple platforms (where platform-specific code is separated into different modules).
除了处理实际的错误情况的异常之外,异常还有其它的用途。在Python标准类库中一个比较常见的用途就是尝试导入一个模块,然后检查模块是否起作用。导入一个不存在的模块将会抛出ImportError 异常,这样你就可以根据那些模块在运行时是否可用,以及是否支持多种平台(平台相关的代码被封装到不同的模块中)来讲模块定义成不同的等级的函数。
You can also define your own exceptions by creating a class that inherits from the built-in Exception class, and then raise your exceptions with the raise command. See the further reading section if you're interested in doing this.
你同样可以定义自己的异常,通过创建一个继承自内置的异常类Exception的类来实现这种功能。使用raise命令,将抛出你自己的异常。如果你对这部分感兴趣,你可以自己参阅相关知识。
The next example demonstrates how to use an exception to support platform-specific functionality. This code comes from the getpass module, a wrapper module for getting a password from the user. Getting a password is accomplished differently on UNIX, Windows, and Mac OS platforms, but this code encapsulates all of those differences.
下面这个例子演示如何使用异常来实现平台相关的功能。这部分代码节选自getpass模块,它是一个获取用户密码的包装类。在Unix,window,mac Os上面获取密码是完全不同的,这部分代码封装了这种差异。
Example 6.2. Supporting Platform-Specific Functionality
例6.2 实现平台相关功能
# Bind the name getpass to the appropriate function
# 为正确的函数查找名为getpass的函数
termios is a UNIX-specific module that provides low-level control over the input terminal. If this module is not available (because it's not on your system, or your system doesn't support it), the import fails and Python raises an ImportError, which you catch termios是一个unix平台相关的模块,它提供了低级的输入控制。如果该模块不可用(如该模块不存在你的平台上,或是你的系统本身不支持该模块),导入就会失败,接着Python将会ImportError异常,你就可以捕捉它。. |
|
OK, you didn't have termios, so let's try msvcrt, which is a Windows-specific module that provides an API to many useful functions in the Microsoft Visual C++ runtime services. If this import fails, Python will raise an ImportError, which you catch. 恩,你的系统没有或是不支持termios,因此我们尝试msvcrt模块,该模块是一个window平台相关的模块。该模块提供了许多API来给Microsoft Visual C++运行的服务提供服务。如果该导入失败,Python将会抛出异常ImportError,你就可以捕捉它。 |
|
If the first two didn't work, you try to import a function from EasyDialogs, which is a Mac OS-specific module that provides functions to pop up dialog boxes of various types. Once again, if this import fails, Python will raise an ImportError, which you catch 如果前两个模块都不起作用,你或许应该尝试从EasyDialogs导入函数,该模块是一个Mac OS平台相关的模块。这个模块提供了函数来弹出不同类型的对话框。同样,如果这次导入失败,Python将会抛出ImportError异常,你就.可以捕捉它。 |
|
None of these platform-specific modules is available (which is possible, since Python has been ported to a lot of different platforms), so you need to fall back on a default password input function (which is defined elsewhere in the getpass module). Notice what you're doing here: assigning the function default_getpass to the variable getpass. If you read the official getpass documentation, it tells you that the getpass module defines a getpass function. It does this by binding getpass to the correct function for your platform. Then when you call the getpass function, you're really calling a platform-specific function that this code has set up for you. You don't need to know or care which platform your code is running on -- just call getpass, and it will always do the right thing. 如果上述平台相关的模块都不可用(这是可能的,这是因为Python可以被移植到许多不同的平台),因此你需要回到一个默认的Password函数(该函数定义在getpass模块中)。值得注意的是:你此处的做法:将默认的getpass赋值给一个变量getpass。如果你阅读官方getpassw文档,你会发现getpass模块定义了一个getpass函数。该函数所作就是将getpass绑定了你平台所对应的正确的函数。接着你就可以调用getpass,你也就真正的调用了一个平台相关的函数,该函数的代码是为你设计的。你不必知道或是关心你的代码到底运行在何种平台---仅仅调用getpass,该函数就会做正确的事。 |
|
A try...except block can have an else clause, like an if statement. If no exception is raised during the try block, the else clause is executed afterwards. In this case, that means that the from EasyDialogs import AskPassword import worked, so you should bind getpass to the AskPassword function. Each of the other try...except blocks has similar else clauses to bind getpass to the appropriate function when you find an import that works. 如同if语句一样,一个try---except代码块可以有else语句,如果在try代码块中没有异常抛出,在try—except 代码块后的第一个else语句在后面直接执行。在本例中,从AskPassword中导入EasyDialog会直接导入,因此你应该将getpass 和AskPassword函数进行绑定。其它的每一个try---except代码块在你发现一个导入模块起作用时,也有同样的else语句来绑定getpass到合适的函数。 |