内置异常

异常名称 说明
ImportError 导入模块失败
EOFError 文件输入指针超出了文件末尾
ValueError 参数的值/类型错误

更多异常可以参考 Built-in Exceptions

处理异常

利用try...except语句使得我们可以处理异常。通常我们将语句放入try块而将错误处理放到except块中。

示例

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/python
# Filename: try_except.py

try:
text = input('Enter something --> ')
except EOFError:
print('Why did you do an EOF on me?')
except KeyboardInterrupt:
print('You cancelled the operation.')
else:
print('You entered {0}'.format(text))

输出

1
2
3
4
5
6
7
8
9
10
11
$ python try_except.py
Enter something --> # Press ctrl-d
Why did you do an EOF on me?

$ python try_except.py
Enter something --> # Press ctrl-c
You cancelled the operation.

$ python try_except.py
Enter something --> no exceptions
You entered no exceptions

引发异常

通过raise语句你可以引发异常。为raise语句提供错误/异常名后异常对象会被抛出。

你抛出的错误或异常必须是一个间接或直接派生自Exception类的类

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/python
# Filename: raising.py

class ShortInputException(Exception):
'''A user-defined exception class.'''
def __init__(self, length, atleast):
Exception.__init__(self)
self.length = length
self.atleast = atleast

try:
text = input('Enter something --> ')
if len(text) < 3:
raise ShortInputException(len(text), 3)
# Other work can continue as usual here
except EOFError:
print('Why did you do an EOF on me?')
except ShortInputException as ex:
print('ShortInputException: The input was {0} long, expected at least {1}'\
.format(ex.length, ex.atleast))
else:
print('No exception was raised.')

输出

1
2
3
4
5
6
7
$ python raising.py
Enter something --> a
ShortInputException: The input was 1 long, expected at least 3

$ python raising.py
Enter something --> abc
No exception was raised.

assert

和很多编程语言一样,Python 有一个assert语句。这是它的用法。

1
2
3
4
5
6
7
8
9
>>> assert 1 + 1 == 2                                     
>>> assert 1 + 1 == 3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError
>>> assert 2 + 2 == 5, "Only for very large values of 2"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError: Only for very large values of 2

如果 Python 表达式求值结果为 False, assert 语句会抛出一个 AssertionError 。

try…finally

假设你的程序正在读取一个文件。如何保证无论是否发生异常文件对象都能被适当的关闭?这可以通过finally块做到。

注意你可以同时为try块关联exceptfinally块。如果你希望同时使用两者则必须将一个嵌入另一个中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/python
# Filename: finally.py

import time

try:
f = open('poem.txt')
while True: # our usual file-reading idiom
line = f.readline()
if len(line) == 0:
break
print(line, end='')
time.sleep(2) # To make sure it runs for a while
except KeyboardInterrupt:
print('!! You cancelled the reading from the file.')
finally:
f.close()
print('(Cleaning up: Closed the file)')

输出

1
2
3
4
5
6
$ python finally.py
Programming is fun
When the work is done
if you wanna make your work also fun:
!! You cancelled the reading from the file.
(Cleaning up: Closed the file)

说明

注意ctrl-c会导致抛出KeyboardInterrupt异常,随后程序结束。但在程序结束前finally会被执行因此文件对象永远都会被关闭。

with语句

try块中获得资源后在finally块中释放之是很常见的设计方式。因此Python提供with语句给予更简洁的实现方式。

1
2
3
4
5
6
#!/usr/bin/python
# Filename: using_with.py

with open("poem.txt") as f:
for line in f:
print(line, end='')

说明

程序的输出应该和上面的范例相同。程序的不同之处在于我们在with语句中使用open函数 —— 如此with语句就会自动关闭文件了。

在幕后with与用户有一个协议。它将读取open语句返回的对象,这里我们将这个对象称为"thefile"。在with块的开始处,with永远都会调用thefile.__enter__方法而在块结束处又会调用thefile.__exit__方法。 因此我们在finally块中的代码被委托给__exit__方法了。这将帮助我们避免反复的使用try..finally块。

从技术上说,with语句创建了一个运行时环境(runtime context)。在这几个样例中,流对象的行为就像一个上下文管理器(context manager)。Python创建了a_file,并且告诉它正进入一个运行时环境。当with块结束的时候,Python告诉流对象它正在退出这个运行时环境,然后流对象就会调用它的close()方法。

任何类只要定义了两个特殊方法:__enter__()__exit__()就可以变成上下文管理器。

深入阅读

Comments