1.2.8. Python 中的异常处理

如果您键入了本教程中之前的所有命令,则很可能已经引发了异常。例如,如果您输入的命令有错别字,则可能会引发异常。

异常是由执行 Python 代码时出现的各种错误引发的。在您自己的代码中,您也可以捕获错误或定义自定义错误类型。在查找正确的异常类型时,您可能需要查看内置异常的描述。

1.2.8.1. 异常

异常是由 Python 中的错误引发的

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

如您所见,针对不同的错误,存在**不同类型**的异常。

1.2.8.2. 捕获异常

try/except

In [8]: while True:
...: try:
...: x = int(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

try/finally

In [10]: try:
....: x = int(input('Please enter a number: '))
....: finally:
....: print('Thank you for your input')
....:
Please enter a number: a
Thank you for your input
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[10], line 2
1 try:
----> 2 x = int(input('Please enter a number: '))
3 finally:
4 print('Thank you for your input')
ValueError: invalid literal for int() with base 10: 'a'

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

寻求宽恕比寻求许可更容易

In [11]: def print_sorted(collection):
....: try:
....: collection.sort()
....: except AttributeError:
....: pass # The pass statement does nothing
....: print(collection)
....:
In [12]: print_sorted([1, 3, 2])
[1, 2, 3]
In [13]: print_sorted(set((1, 3, 2)))
{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ël'
    In [17]: filter_name('Stéfan')
    ---------------------------------------------------------------------------
    UnicodeEncodeError Traceback (most recent call last)
    Cell In[17], line 1
    ----> 1 filter_name('Stéfan')
    Cell In[15], line 8, in filter_name(name)
    6 print('OK, Gaël')
    7 else:
    ----> 8 raise e
    9 return name
    Cell In[15], line 3, in filter_name(name)
    1 def filter_name(name):
    2 try:
    ----> 3 name = name.encode('ascii')
    4 except UnicodeError as e:
    5 if name == 'Gaël':
    UnicodeEncodeError: 'ascii' codec can't encode character '\xe9' in position 2: ordinal not in range(128)
  • 异常用于在代码的不同部分之间传递消息

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

使用异常来通知某些条件是否满足(例如 StopIteration)或不满足(例如自定义错误引发)