1.2.8. Python中的异常处理

如果你键入了本教程的所有以前的命令,你可能已经引发过异常。例如,如果输入具有拼写错误的命令,则可能引发了异常。

执行Python代码时出现的不同类型的错误会引发异常。在你自己的代码中,你还可以捕获错误,或定义自定义错误类型。在查找正确的异常类型时,你可能需要查看内置异常的说明。

1.2.8.1. 异常

异常由Python中的错误引发:

In [1]: 1/0
---------------------------------------------------------------------------
ZeroDivisionError: integer division or modulo by zero
In [2]: 1 + 'e'
---------------------------------------------------------------------------
TypeError: unsupported operand type(s) for +: 'int' and 'str'
In [3]: d = {1:1, 2:2}
In [4]: d[3]
---------------------------------------------------------------------------
KeyError: 3
In [5]: l = [1, 2, 3]
In [6]: l[4]
---------------------------------------------------------------------------
IndexError: list index out of range
In [7]: l.foobar
---------------------------------------------------------------------------
AttributeError: 'list' object has no attribute 'foobar'

如你所见,对于不同错误,异常的类型不同

1.2.8.2. 捕获异常

1.2.8.2.1. try/except

In [10]: while True:
....: try:
....: x = int(raw_input('Please enter a number: '))
....: break
....: except ValueError:
....: print('That was no valid number. Try again...')
....:
Please enter a number: a
That was no valid number. Try again...
Please enter a number: 1
In [9]: x
Out[9]: 1

1.2.8.2.2. try/finally

In [10]: try:
....: x = int(raw_input('Please enter a number: '))
....: finally:
....: print('Thank you for your input')
....:
....:
Please enter a number: a
Thank you for your input
---------------------------------------------------------------------------
ValueError: invalid literal for int() with base 10: 'a'

对资源管理重要(例如关闭文件)

1.2.8.2.3. 请求原谅比请求权限更容易

In [11]: def print_sorted(collection):
....: try:
....: collection.sort()
....: except AttributeError:
....: pass
....: print(collection)
....:
....:
In [12]: print_sorted([1, 3, 2])
[1, 2, 3]
In [13]: print_sorted(set((1, 3, 2)))
set([1, 2, 3])
In [14]: print_sorted('132')
132

1.2.8.3. 引发异常

  • 捕获和重新引发异常:

    In [15]: def filter_name(name):
    
    ....: try:
    ....: name = name.encode('ascii')
    ....: except UnicodeError as e:
    ....: if name == 'Gaël':
    ....: print('OK, Gaël')
    ....: else:
    ....: raise e
    ....: return name
    ....:
    In [16]: filter_name('Gaël')
    OK, Gaël
    Out[16]: 'Ga\xc3\xabl'
    In [17]: filter_name('Stéfan')
    ---------------------------------------------------------------------------
    UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 2: ordinal not in range(128)
  • 用异常在代码各个部分之间传递消息:

    In [17]: def achilles_arrow(x):
    
    ....: if abs(x - 1) < 1e-3:
    ....: raise StopIteration
    ....: x = 1 - (1-x)/2.
    ....: return x
    ....:
    In [18]: x = 0
    In [19]: while True:
    ....: try:
    ....: x = achilles_arrow(x)
    ....: except StopIteration:
    ....: break
    ....:
    ....:
    In [20]: x
    Out[20]: 0.9990234375

使用异常来通知某些条件是符合(例如StopIteration)还是不符合(例如自定义错误)