The Python Tutorial 3.2 - 8Errors and Exceptions(错误和异常)

来源:互联网 发布:网络招商推广方案 编辑:程序博客网 时间:2024/05/13 19:57

8. Errors and Exceptions错误和异常


Until now error messages haven’t been more than mentioned, but if you have tried out the examples you have probably seen some. There are (at least) two distinguishable kinds of errors: syntax errors and exceptions.

直到现在,我们仍未提及错误信息,但如果你试验过示例,你大概已经看过一些。这里有(至少)两种不同类型的错误:语法错误异常

8.1. Syntax Errors语法错误

Syntax errors, also known as parsing errors, are perhaps the most common kind of complaint you get while you are still learning Python:

语法错误,也称作解析错误,也许是你学习Python过程中最常见抱怨。

>>> while True print('Hello world')  File "", line 1, in ?    while True print('Hello world')                   ^SyntaxError: invalid syntax

The parser repeats the offending line and displays a little ‘arrow’ pointing at the earliest point in the line where the error was detected. The error is caused by (or at least detected at) the token preceding the arrow: in the example, the error is detected at the function print(), since a colon (':') is missing before it. File name and line number are printed so you know where to look in case the input came from a script.

语法分析器重复输出错误行,并且在错误被检测到的最初位置前面显示一个小“箭头”。错误是由箭头前面标记引起的(或者至少是检测所在):这个例子中,函数 print() 被发现存在错误,因为它前面少了一个冒号( ':' )。如果是从脚本输入,错误会输出文件名和行号,所以你就知道去哪里检查错误了。

8.2. Exceptions异常

Even if a statement or expression is syntactically correct, it may cause an error when an attempt is made to execute it. Errors detected during execution are called exceptions and are not unconditionally fatal: you will soon learn how to handle them in Python programs. Most exceptions are not handled by programs, however, and result in error messages as shown here:

即使一条语句或表达式在语法上是正确的,当试图执行它时也可能会引发错误。运行期检测到的错误称为异常,并且程序不会无条件崩溃:很快你将学到如何在Python程序中处理它们。大多数异常都不会被程序处理,然而,像这样会引起像如图所示的错误信息:

>>> 10 * (1/0)Traceback (most recent call last):  File "", line 1, in ?ZeroDivisionError: int division or modulo by zero>>> 4 + spam*3Traceback (most recent call last):  File "", line 1, in ?NameError: name 'spam' is not defined>>> '2' + 2Traceback (most recent call last):  File "", line 1, in ?TypeError: Can't convert 'int' object to str implicitly

The last line of the error message indicates what happened. Exceptions come in different types, and the type is printed as part of the message: the types in the example areZeroDivisionError, NameError and TypeError. The string printed as the exception type is the name of the built-in exception that occurred. This is true for all built-in exceptions, but need not be true for user-defined exceptions (although it is a useful convention). Standard exception names are built-in identifiers (not reserved keywords).

错误信息最后一行指明发生了什么。异常是以不同的类型出现的,并且类型也被当做信息的一部分打印出来:示例中包含 ZeroDivisionError , NameError 和 TypeError 类型。异常发生时打印的异常类型字符串就是内置异常的名称。这适合于内置异常,但不一定适合于自定义异常(尽管这是一个有用的规范)。标准异常的名称都是内置标识符(非保留关键字)。

The rest of the line provides detail based on the type of exception and what caused it.

这行剩余部分提供了基于异常类型和引发异常相关的详细信息。

The preceding part of the error message shows the context where the exception happened, in the form of a stack traceback. In general it contains a stack traceback listing source lines; however, it will not display lines read from standard input.

异常信息的前面部分以堆栈回溯的形式显示了异常发生的上下文。通常,它包含一个堆栈回溯的源代码行的清单,但从标准输入读取的行不会被显示。

Built-in Exceptions lists the built-in exceptions and their meanings.

内置exception文档列出了内置异常及其用途。

8.3. Handling Exceptions异常处理

It is possible to write programs that handle selected exceptions. Look at the following example, which asks the user for input until a valid integer has been entered, but allows the user to interrupt the program (using Control-C or whatever the operating system supports); note that a user-generated interruption is signalled by raising the KeyboardInterrupt exception.

通过编程处理选择的异常是可行的。看下面的例,它会一直要求用户输入,直到输入一个合法的整数为止,但允许用户中断这个程序(使用 Control-C 或系统支持的任何方法)。注意:用户产生的中断会引发一个 KeyboardInterrupt 异常。

>>> while True:...     try:...         x = int(input("Please enter a number: "))...         break...     except ValueError:...         print("Oops!  That was no valid number.  Try again...")...

The try statement works as follows.

try语句按如下方式工作:

  • First, the try clause (the statement(s) between the try and except keywords) is executed.
  • 首先,执行try子句(在try与except关键字之间的语句)
  • If no exception occurs, the except clause is skipped and execution of the try statement is finished.
  • 如果没有异常发生,except子句就会被跳过,try语句执行完毕
  • If an exception occurs during execution of the try clause, the rest of the clause is skipped. Then if its type matches the exception named after the except keyword, the except clause is executed, and then execution continues after the try statement.
  • 如果在执行try子句时发生异常,子句的剩余部分被跳过。如果异常的类型与 except 后面的异常名称相匹配,那么 except 子句就会被执行,然后继续执行 try 语句之后的代码。
  • If an exception occurs which does not match the exception named in the except clause, it is passed on to outer try statements; if no handler is found, it is an unhandled exception and execution stops with a message as shown above.
  • 如果一个异常没有任何 except 子句中的异常名称与之匹配,那么它就会被传递try 语句外层 ;如果仍然没有找到处理这个异常的语句,它就成了一个未处理的异常并且中止代码执行,像上面那样显示一条信息。

A try statement may have more than one except clause, to specify handlers for different exceptions. At most one handler will be executed. Handlers only handle exceptions that occur in the corresponding try clause, not in other handlers of the same try statement. An except clause may name multiple exceptions as a parenthesized tuple, for example:

一个 try 语句可以有多个 except 子句,用来明确的处理不同的异常。最多只有一个异常处理子句会被执行。异常处理子句只处理对应的 try 子句中发生的异常,而不是其他的 try 语句发生的异常。一个 except 子句可以通过带括号的元组(tuple)定义多个异常类型,例如:

... except (RuntimeError, TypeError, NameError):...     pass

The last except clause may omit the exception name(s), to serve as a wildcard. Use this with extreme caution, since it is easy to mask a real programming error in this way! It can also be used to print an error message and then re-raise the exception (allowing a caller to handle the exception as well):

最后一个 except 子句可以省略异常名称,以作为通配符使用。你需要慎用此法,因为它会轻易隐藏一个实际的程序错误!可以使用这种方法打印一条错误信息,然后重新抛出异常(允许调用者处理这个异常)。

import systry:    f = open('myfile.txt')    s = f.readline()    i = int(s.strip())except IOError as err:    print("I/O error: {0}".format(err))except ValueError:    print("Could not convert data to an integer.")except:    print("Unexpected error:", sys.exc_info()[0])    raise

The try ... except statement has an optional else clause, which, when present, must follow all except clauses. It is useful for code that must be executed if the try clause does not raise an exception. For example:

try...except语句有一个可选的else子句,如果存此子句,它必须在所在except子句之后。这对那些如果 try 子句没有抛出异常必须执行的代码就非常有用。

for arg in sys.argv[1:]:    try:        f = open(arg, 'r')    except IOError:        print('cannot open', arg)    else:        print(arg, 'has', len(f.readlines()), 'lines')        f.close()

The use of the else clause is better than adding additional code to the try clause because it avoids accidentally catching an exception that wasn’t raised by the code being protected by the try ... except statement.

使用 else 子句比向 try 子句添加额外的代码更好,因为它避免了意外捕获的异常,它们并不是由 try...except 语句保护的代码所抛出。

When an exception occurs, it may have an associated value, also known as the exception’s argument. The presence and type of the argument depend on the exception type.

当一个异常发生时,它可能含有一个相关值,又称为异常参数。是否存在此参数及其类型取决于异常的类型。

The except clause may specify a variable after the exception name. The variable is bound to an exception instance with the arguments stored in instance.args. For convenience, the exception instance defines __str__() so the arguments can be printed directly without having to reference .args. One may also instantiate an exception first before raising it and add any attributes to it as desired.

except 子句可以在异常名称后面指定一个变量。这个变量以存储在 instance.args 中的参数形式绑定到一个异常实例。方便起见,异常实例定义了 __str__() 方法,所以这个参数可以被直接打印出来而无需通过 .args 引用。你也可以在抛出异常前先实例化它,然后给它添加任何想要的属性。

>>> try:...    raise Exception('spam', 'eggs')... except Exception as inst:...    print(type(inst))    # the exception instance...    print(inst.args)     # arguments stored in .args...    print(inst)          # __str__ allows args to be printed directly,...                         # but may be overridden in exception subclasses...    x, y = inst.args     # unpack args...    print('x =', x)...    print('y =', y)...('spam', 'eggs')('spam', 'eggs')x = spamy = eggs

If an exception has arguments, they are printed as the last part (‘detail’) of the message for unhandled exceptions.

对于那些未处理的异常,如果一个它们带有参数,那么就会被作为异常信息的最后部分(“详情”)打印出来。

Exception handlers don’t just handle exceptions if they occur immediately in the try clause, but also if they occur inside functions that are called (even indirectly) in the try clause. For example:

异常处理器不仅仅处理那些在 try 子句中立刻发生的异常,也会处理那些 try 子句中调用的函数内部发生的异常。例如:

>>> def this_fails():...     x = 1/0...>>> try:...     this_fails()... except ZeroDivisionError as err:...     print('Handling run-time error:', err)...Handling run-time error: int division or modulo by zero

8.4. Raising Exceptions抛出异常

The raise statement allows the programmer to force a specified exception to occur. For example:

raise 语句允许程序员强制抛出一个指定的异常。例如:

>>> raise NameError('HiThere')Traceback (most recent call last):  File "", line 1, in ?NameError: HiThere

The sole argument to raise indicates the exception to be raised. This must be either an exception instance or an exception class (a class that derives from Exception).

raise 唯一的参数指定了要抛出的异常。它必须是一个异常实例,或者是异常类(继承自 Exception 的类)。

If you need to determine whether an exception was raised but don’t intend to handle it, a simpler form of the raise statement allows you to re-raise the exception:

如果你需要确定是否抛出了一个异常而并不想去处理它,一个更简单方式就是 raise 语句,允许你重新抛出异常。

>>> try:...     raise NameError('HiThere')... except NameError:...     print('An exception flew by!')...     raise...An exception flew by!Traceback (most recent call last):  File "", line 2, in ?NameError: HiThere

8.5. User-defined Exceptions自定义异常

Programs may name their own exceptions by creating a new exception class (see Classes for more about Python classes). Exceptions should typically be derived from the Exception class, either directly or indirectly. For example:

通过创建一个新的异常类,程序可以命名它们自己的异常。异常往往应该是通过直接或间接的方式继承自 Exception 类。例如:

>>> class MyError(Exception):...     def __init__(self, value):...         self.value = value...     def __str__(self):...         return repr(self.value)...>>> try:...     raise MyError(2*2)... except MyError as e:...     print('My exception occurred, value:', e.value)...My exception occurred, value: 4>>> raise MyError('oops!')Traceback (most recent call last):  File "", line 1, in ?__main__.MyError: 'oops!'

In this example, the default __init__() of Exception has been overridden. The new behavior simply creates the value attribute. This replaces the default behavior of creating the args attribute.

在这个列子中, Exception 的默认方法 __init__() 被覆盖。新的行为只是简单的创建 value 属性。这替换了创建 args 属性的默认行为。

Exception classes can be defined which do anything any other class can do, but are usually kept simple, often only offering a number of attributes that allow information about the error to be extracted by handlers for the exception. When creating a module that can raise several distinct errors, a common practice is to create a base class for exceptions defined by that module, and subclass that to create specific exception classes for different error conditions:

异常类可以定义成像其他类一样做任何事情,但一般都会保持简洁,通常只提供一些属性以便于异常处理器获取错误相关信息。当创建一个可以产生几种不同错误的模块时,一种通常的做法是为模块中定义的异常创建一个基础类,然后为不同的错误情况创建特定的子异常类。

class Error(Exception):    """Base class for exceptions in this module."""    passclass InputError(Error):    """Exception raised for errors in the input.    Attributes:        expression -- input expression in which the error occurred        message -- explanation of the error    """    def __init__(self, expression, message):        self.expression = expression        self.message = messageclass TransitionError(Error):    """Raised when an operation attempts a state transition that's not    allowed.    Attributes:        previous -- state at beginning of transition        next -- attempted new state        message -- explanation of why the specific transition is not allowed    """    def __init__(self, previous, next, message):        self.previous = previous        self.next = next        self.message = message

Most exceptions are defined with names that end in “Error,” similar to the naming of the standard exceptions.

大多数异常的名字都是以“Error”结尾,类似标准异常命名。

Many standard modules define their own exceptions to report errors that may occur in functions they define. More information on classes is presented in chapter Classes.

许多标准模块定义它们自己的异常来报告那些可能发生在函数中错误。更多关于类的信息请参考 Classes 类 章节。

8.6. Defining Clean-up Actions定义清理动作

The try statement has another optional clause which is intended to define clean-up actions that must be executed under all circumstances. For example:

try 语句有另外一个可选的子句,可以用来定义那些在任何情况下必须执行的清理动作。例如:

>>> try:...     raise KeyboardInterrupt... finally:...     print('Goodbye, world!')...Goodbye, world!KeyboardInterrupt

A finally clause is always executed before leaving the try statement, whether an exception has occurred or not. When an exception has occurred in the try clause pand has not been handled by an except clause (or it has occurred in a except or else clause), it is re-raised after the finally clause has been executed. The finally clause is also executed “on the way out” when any other clause of the try statement is left via a break, continue or return statement. A more complicated example:

无论是否发生异常,一个 finally 子句在离开 try 语句前总是会被执行。当在 try 子句中发生一个异常并且没有被 except 字句处理时(或者发生在 except 或 else 子句中),它将会在 finally 子句执行完后被重新抛出。即使通过 break , continue 或者 return 等其他任何子句,当要离开try语句时 finally 子句也会被执行。一个稍微复杂的列子:

>>> def divide(x, y):...     try:...         result = x / y...     except ZeroDivisionError:...         print("division by zero!")...     else:...         print("result is", result)...     finally:...         print("executing finally clause")...>>> divide(2, 1)result is 2.0executing finally clause>>> divide(2, 0)division by zero!executing finally clause>>> divide("2", "1")executing finally clauseTraceback (most recent call last):  File "", line 1, in ?  File "", line 3, in divideTypeError: unsupported operand type(s) for /: 'str' and 'str'

As you can see, the finally clause is executed in any event. The TypeError raised by dividing two strings is not handled by the except clause and therefore re-raised after the finally clause has been executed.

如你所见,在任何事件下 finally 子句都会执行。通过将两个字符串相除引发的 TypeError 异常并没有被 except 字句处理,因此在 finally 子句执行后被重新抛出。

In real world applications, the finally clause is useful for releasing external resources (such as files or network connections), regardless of whether the use of the resource was successful.

在真实的应用程式中,使用 finally 子句释放额外的资源(像文件或网络连接)是有用的选择,不论对资源的操作是否成功。

8.7. Predefined Clean-up Actions预定义清理动作

Some objects define standard clean-up actions to be undertaken when the object is no longer needed, regardless of whether or not the operation using the object succeeded or failed. Look at the following example, which tries to open a file and print its contents to the screen.

一些对象定义了标准的清理动作,无论使用对象的操作是否成功,当对象不再需要时它们就在后台被调用执行。下面的例子尝试打开一个文件并将其内容打印在屏幕上。

for line in open("myfile.txt"):    print(line)

The problem with this code is that it leaves the file open for an indeterminate amount of time after this part of the code has finished executing. This is not an issue in simple scripts, but can be a problem for larger applications. The with statement allows objects like files to be used in a way that ensures they are always cleaned up promptly and correctly.

这段代码的问题是当代码执行完毕后不知会过多久它才会关闭文件。这在简单的脚本中还不构成额外难题,但在大的应用程式中问题就严重了。 with 语句保证像文件这样的对象在使用完之后总是可以被立即正确的清理。

with open("myfile.txt") as f:    for line in f:        print(line)

After the statement is executed, the file f is always closed, even if a problem was encountered while processing the lines. Objects which, like files, provide predefined clean-up actions will indicate this in their documentation.

在这段语句执行后,文件 f 总是被关闭,甚至在处理文件行时遇到了问题。诸如文件之类的对象在它们的文档中会指出是否提供了预定义清理动作。

原创粉丝点击