天天看點

Python 2.7 Tutorial —— 錯誤和異常

.. _tut-errors:

==================================

 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*.

至今為止還沒有進一步的談論過錯誤資訊,不過在你已經試驗過的那些例子中,

可能已經遇到過一些。Python 中(至少)有兩種錯誤:文法錯誤和異常

( *syntax errors* and *exceptions* )。

.. _tut-syntaxerrors:

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 "<stdin>", 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 keyword :keyword:`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.

解析器會重複出錯的行,并在行中最早發現的錯誤位置上顯示一個小“箭頭”。錯誤

(至少是被檢測到的)就發生在箭頭 *指向* 的位置。示例中的錯誤表現在關鍵字

:keyword:`print` 上,因為在它之前少了一個冒号( ``':'`` )。同時也會顯示檔案名和行号,

這樣你就可以知道錯誤來自哪個腳本,什麼位置。 

.. _tut-exceptions:

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 "<stdin>", line 1, in ?

   ZeroDivisionError: integer division or modulo by zero

   >>> 4 + spam*3

   Traceback (most recent call last):

     File "<stdin>", line 1, in ?

   NameError: name 'spam' is not defined

   >>> '2' + 2

   Traceback (most recent call last):

     File "<stdin>", line 1, in ?

   TypeError: cannot concatenate 'str' and 'int' objects

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 are :exc:`ZeroDivisionError`, :exc:`NameError` and :exc:`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).

錯誤資訊的最後一行指出發生了什麼錯誤。異常也有不同的類型,異常類型做為

錯誤資訊的一部分顯示出來:示例中的異常分别為 零除錯誤

( :exc:`ZeroDivisionError` ) ,命名錯誤( :exc:`NameError`) 和 類型

錯誤(:exc:`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.

錯誤資訊的前半部分以堆棧的形式列出異常發生的位置。通常在堆棧中列出了源代碼行,然而,來自标準輸入的源碼不會顯示出來。

:ref:`bltin-exceptions` lists the built-in exceptions and their meanings.

:ref:`bltin-exceptions` 列出了内置異常和它們的含義。

.. _tut-handling:

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 :kbd:`Control-C` or

whatever the operating system supports); note that a user-generated interruption

is signalled by raising the :exc:`KeyboardInterrupt` exception. :

可以編寫程式來控制已知的異常。參見下例,此示例要求使用者輸入資訊,一直到

得到一個有效的整數為止,而且允許使用者中斷程式(使用 :kbd:`Control-C` 或

其它什麼作業系統支援的操作);需要注意的是使用者生成的中斷會抛出

:exc:`KeyboardInterrupt` 異常。 ::

   >>> while True:

   ...     try:

   ...         x = int(raw_input("Please enter a number: "))

   ...         break

   ...     except ValueError:

   ...         print "Oops!  That was no valid number.  Try again..."

   ...

The :keyword:`try` statement works as follows.

:keyword:`try` 語句按如下方式工作。

* First, the *try clause* (the statement(s) between the :keyword:`try` and

  :keyword:`except` keywords) is executed.

  首先,執行 *try 子句* (在 :keyword:`try` 和 :keyword:`except` 關鍵字之間的部分)。

* If no exception occurs, the *except clause* is skipped and execution of the

  :keyword:`try` statement is finished.

  如果沒有異常發生, *except 子句* 在 :keyword:`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

  :keyword:`except` keyword, the except clause is executed, and then execution

  continues after the :keyword:`try` statement.

  如果在 try 子句執行過程中發生了異常,那麼該子句其餘的部分就會被忽略。

  如果異常比對于 :keyword:`except` 關鍵字後面指定的異常類型,就執行對應的except子

  句。然後繼續執行 :keyword:`try` 語句之後的代碼。

* If an exception occurs which does not match the exception named in the except

  clause, it is passed on to outer :keyword:`try` statements; if no handler is

  found, it is an *unhandled exception* and execution stops with a message as

  shown above.

  如果發生了一個異常,在 except 子句中沒有與之比對的分支,它就會傳遞到

  上一級 :keyword:`try` 語句中。如果最終仍找不到對應的處理語句,它就成

  為一個 *未處理異常* ,終止程式運作,顯示提示資訊。

A :keyword:`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 :keyword:`try` statement.  An except clause may

name multiple exceptions as a parenthesized tuple, for example:

一個 :keyword:`try` 語句可能包含多個 except 子句,分别指定處理不同的異

常。至多隻會有一個分支被執行。異常處理程式隻會處理對應的 try 子句中發

生的異常,在同一個 :keyword:`try` 語句中,其他子句中發生的異常則不作處

理。一個except子句可以在括号中列出多個異常的名字,例如 ::

   ... 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 sys

   try:

       f = open('myfile.txt')

       s = f.readline()

       i = int(s.strip())

   except IOError as (errno, strerror):

       print "I/O error({0}): {1}".format(errno, strerror)

   except ValueError:

       print "Could not convert data to an integer."

   except:

       print "Unexpected error:", sys.exc_info()[0]

       raise

The :keyword:`try` ... :keyword:`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:

:keyword:`try` ... :keyword:`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 :keyword:`else` clause is better than adding additional code to

the :keyword:`try` clause because it avoids accidentally catching an exception

that wasn't raised by the code being protected by the :keyword:`try` ...

:keyword:`except` statement.

使用 :keyword:`else` 子句比在 :keyword:`try` 子句中附加代碼要好,因為

這樣可以避免 :keyword:`try` ... :keyword:`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 (or tuple).

The variable is bound to an exception instance with the arguments stored in

``instance.args``.  For convenience, the exception instance defines

:meth:`__str__` so the arguments can be printed directly without having to

reference ``.args``.

在異常名(清單)之後,也可以為 except 子句指定一個變量。這個變量綁定于

一個異常執行個體,它存儲在 ``instance.args`` 的參數中。為了友善起見,異常執行個體

定義了 :meth:`__str__` ,這樣就可以直接通路過列印參數而不必引用

``.args`` 。 

One may also instantiate an exception first before raising it and add any

attributes to it as desired. :

這種做法不受鼓勵。相反,更好的做法是給異常傳遞一個參數(如果要傳遞多個

參數,可以傳遞一個元組),把它綁定到 message 屬性。一旦異常發生,它會

在抛出前綁定所有指定的屬性。 ::

   >>> 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 printed directly

   ...    x, y = inst          # __getitem__ allows args to be unpacked directly

   ...    print 'x =', x

   ...    print 'y =', y

   ...

   <type 'exceptions.Exception'>

   ('spam', 'eggs')

   ('spam', 'eggs')

   x = spam

   y = eggs

If an exception has an argument, it is 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 子句中的異常,即使是其中(甚至

是間接)調用的函數,發生了異常,也一樣可以處理。例如 ::

   >>> def this_fails():

   ...     x = 1/0

   ...

   >>> try:

   ...     this_fails()

   ... except ZeroDivisionError as detail:

   ...     print 'Handling run-time error:', detail

   ...

   Handling run-time error: integer division or modulo by zero

.. _tut-raising:

Raising Exceptions 抛出異常

===========================

The :keyword:`raise` statement allows the programmer to force a specified

exception to occur. For example:

程式員可以用 :keyword:`raise` 語句強制指定的異常發生。例如 ::

   >>> raise NameError('HiThere')

   Traceback (most recent call last):

     File "<stdin>", line 1, in ?

   NameError: HiThere

The sole argument to :keyword:`raise` indicates the exception to be raised.

This must be either an exception instance or an exception class (a class that

derives from :class:`Exception`).

要抛出的異常由 :keyword:`raise` 的唯一參數辨別。它必需是一個異常執行個體或

異常類(繼承自 :class:`Exception` 的類)。

If you need to determine whether an exception was raised but don't intend to

handle it, a simpler form of the :keyword:`raise` statement allows you to

re-raise the exception:

如果你需要明确一個異常是否抛出,但不想處理它, :keyword:`raise` 

語句可以讓你很簡單的重新抛出該異常。

   >>> try:

   ...     raise NameError('HiThere')

   ... except NameError:

   ...     print 'An exception flew by!'

   ...     raise

   ...

   An exception flew by!

   Traceback (most recent call last):

     File "<stdin>", line 2, in ?

   NameError: HiThere

.. _tut-userexceptions:

User-defined Exceptions 使用者自定義異常

======================================

Programs may name their own exceptions by creating a new exception class (see

:ref:`tut-classes` for more about Python classes).  Exceptions should typically

be derived from the :exc:`Exception` class, either directly or indirectly.  For

example:

在程式中可以通過建立新的異常類型來命名自己的異常(Python 類的内容請參

見 :ref:`tut-classes` )。異常類通常應該直接或間接的從

:exc:`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 "<stdin>", line 1, in ?

   __main__.MyError: 'oops!'

In this example, the default :meth:`__init__` of :class:`Exception` has been

overridden.  The new behavior simply creates the *value* attribute.  This

replaces the default behavior of creating the *args* attribute.

在這個例子中,:class:`Exception` 預設的 :meth:`__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."""

       pass

   class InputError(Error):

       """Exception raised for errors in the input.

       Attributes:

           expr -- input expression in which the error occurred

           msg  -- explanation of the error

       """

       def __init__(self, expr, msg):

           self.expr = expr

           self.msg = msg

   class TransitionError(Error):

       """Raised when an operation attempts a state transition that's not

       allowed.

       Attributes:

           prev -- state at beginning of transition

           next -- attempted new state

           msg  -- explanation of why the specific transition is not allowed

       """

       def __init__(self, prev, next, msg):

           self.prev = prev

           self.next = next

           self.msg = msg

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 :ref:`tut-classes`.

很多标準子產品中都定義了自己的異常,用以報告在他們所定義的函數中可能發生

的錯誤。關于類的進一步資訊請參見 :ref:`tut-classes` 一章。

.. _tut-cleanup:

Defining Clean-up Actions 定義清理行為

====================================================

The :keyword:`try` statement has another optional clause which is intended to

define clean-up actions that must be executed under all circumstances.  For

example:

:keyword:`try` 語句還有另一個可選的子句,目的在于定義在任何情況下都一定要執行的功

能。例如 ::

   >>> try:

   ...     raise KeyboardInterrupt

   ... finally:

   ...     print 'Goodbye, world!'

   ...

   Goodbye, world!

   Traceback (most recent call last):

     File "<stdin>", line 2, in ?

   KeyboardInterrupt

A *finally clause* is always executed before leaving the :keyword:`try`

statement, whether an exception has occurred or not. When an exception has

occurred in the :keyword:`try` clause and has not been handled by an

:keyword:`except` clause (or it has occurred in a :keyword:`except` or

:keyword:`else` clause), it is re-raised after the :keyword:`finally` clause has

been executed.  The :keyword:`finally` clause is also executed "on the way out"

when any other clause of the :keyword:`try` statement is left via a

:keyword:`break`, :keyword:`continue` or :keyword:`return` statement.  A more

complicated example (having :keyword:`except` and :keyword:`finally` clauses in

the same :keyword:`try` statement works as of Python 2.5):

不管有沒有發生異常, *finally 子句* 在程式離開 :keyword:`try` 後都一定

會被執行。當 :keyword:`try` 語句中發生了未被 :keyword:`except` 捕獲的

異常(或者它發生在 :keyword:`except` 或 :keyword:`else` 子句中),在

:keyword:`finally` 子句執行完後它會被重新抛出。 :keyword:`try` 語句經

由 :keyword:`break` ,:keyword:`continue` 或 :keyword:`return` 語句退

出也一樣會執行 :keyword:`finally` 子句。以下是一個更複雜些的例子(在同

一個 :keyword:`try` 語句中的 :keyword:`except` 和 :keyword:`finally`

子句的工作方式與 Python 2.5 一樣) ::

   >>> 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

   executing finally clause

   >>> divide(2, 0)

   division by zero!

   executing finally clause

   >>> divide("2", "1")

   executing finally clause

   Traceback (most recent call last):

     File "<stdin>", line 1, in ?

     File "<stdin>", line 3, in divide

   TypeError: unsupported operand type(s) for /: 'str' and 'str'

As you can see, the :keyword:`finally` clause is executed in any event.  The

:exc:`TypeError` raised by dividing two strings is not handled by the

:keyword:`except` clause and therefore re-raised after the :keyword:`finally`

clause has been executed.

如你所見, :keyword:`finally` 子句在任何情況下都會執

行。 :exc:`TypeError`

在兩個字元串相除的時候抛出,未被 :keyword:`except` 子句捕獲,是以在

:keyword:`finally` 子句執行完畢後重新抛出。

In real world applications, the :keyword:`finally` clause is useful for

releasing external resources (such as files or network connections), regardless

of whether the use of the resource was successful.

在真實場景的應用程式中, :keyword:`finally` 子句用于釋放外部資源(檔案

或網絡連接配接之類的),無論它們的使用過程中是否出錯。

.. _tut-cleanup-with:

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 the code has finished executing. This is not an issue in

simple scripts, but can be a problem for larger applications. The

:keyword:`with` statement allows objects like files to be used in a way that

ensures they are always cleaned up promptly and correctly. :

這段代碼的問題在于在代碼執行完後沒有立即關閉打開的檔案。這在簡單的腳本

裡沒什麼,但是大型應用程式就會出問題。 :keyword:`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. Other objects which provide

predefined clean-up actions will indicate this in their documentation.

語句執行後,檔案 *f* 總會被關閉,即使是在處理檔案中的資料時出錯也一樣。

其它對象是否提供了預定義的清理行為要檢視它們的文檔。