文章目录
异常
在编写程序的时候, 程序员通常要辨别事件的正常过程和异常的情况. 这类异常事件可能是错误, 或者是不希望经常发生的事情. 为了能够处理这些异常事件, python提供了非常强大的替代解决方案. 本章介绍如何创建和引发自定义的异常, 以及处理异常的各种方法。
8.1 什么是异常
python用异常对象(exception object)来表示异常情况. 遇到错误后, 会引发异常. 如果异常对象并未被处理或者捕捉, 程序就会进行回溯(traceback)中止执行.
1 2 3 4 5 |
>>> 1/0 Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: division by zero |
每个异常都是一些类的实例, 这些实例可以被引发, 也可以通过多种方式进行捕捉, 使得程序可以捉住错误并且对其进行处理, 而不是让整个程序失效.
8.2 按自己的方式出错
异常在有错误出现时自动引发
8.2.1 引发语句
为了引发异常, 可以使用一个类 ( Exception的子类 ) 或者实例参数调用 raise 语句. 使用类时, 程序会自动创建一个类的实例
1 2 3 4 5 6 7 8 9 |
>>> raise Exception Traceback (most recent call last): File "<stdin>", line 1, in <module> Exception >>> raise Exception('hyperdriver overload') Traceback (most recent call last): File "<stdin>", line 1, in <module> Exception: hyperdriver overload |
第一个例子 raise Exception 引发了一个没有任何有关错误信息的普通异常。后一个例子添加了有关异常的信息。
内建的异常类型很多, built-in Exceptions(位于python库参考手册中)有关于他们的描述。这些异常都可以在Exception模块中找到
类型名 | 描述 |
---|---|
Exception | 所有异常的基类 |
AttributeError | 特征引用或者赋值失败时 |
IOError | 试图打开不存在的文件(或者其他情况时打开) |
IndexError | 使用序列中不存在的索引值时引发 |
KeyError | 在使用映射中不存在的键时引发 |
NameError | 找不到名字或者变量时候引发 |
SyntaxError | 代码为错误形式时引发 |
TypeError | 在内建操作或者函数用于错误类型的对象时引发 |
ValueError | 在内建操作或者函数用于正确的对象,但是对象的使用不合适的值时引发 |
ZeroDivisionError | 再除法或者除模操作的第二个参数为0时引发 |
8.2.2 自定义异常类
内建的异常类尽管已经包含了大部分的情况,而且对于很多情况的要求已经足够了。
但是总有万一,那么我们可以建设自己的异常类
1 2 |
class SomeCustomException(Exception): pass |
8.3 捕捉异常
使用 try/except 语句可以实现捕捉异常:
1 2 3 4 5 6 7 |
try: x=input('Enter the first number:') y=input('Enter the second number:') print(x/y) except ZeroException: print("The Second number can't be zero) |
如果没有捕捉异常,它就会被传播到外层作用域中。
看,没参数
如果捕捉到了异常又想要重新引发它,那么可以调用不带参数的 raise
1 2 3 4 5 6 7 8 9 10 11 |
class MuffledCalculator: muffed = False def calc(self,expr): try: return eval(expr) except ZeroDivisionError: if self.muffled: print('Division by zero is illegal') else raise |
在和用户交互的过程中,使用屏蔽的效果更佳,但在程序内部传播,使用异常更好
8.4 不止一个 except 子句
1 2 3 4 5 6 7 8 9 |
try: x=input('Enter the first number:') y=input('Enter the second number:') print(x/y) except ZeroDivisionError: print("The second number can't be zero") except TypeError: print("That wasn't a number, was it?") |
8.5 用一个块捕捉两个异常
1 2 3 4 5 |
try: pass except (error1[,error2[,..]]): pass |
8.6 捕捉对象
- 如果希望 except 子句访问异常对象本身,可以使用两个参数
- 就算要捕捉多个异常,也只需要向 except 的第一个参数传递一个元组
1 2 3 4 5 6 |
try: pass except (error1[,error2[,..]]) as e: print(e) #在python2中,except子句为except (error1[,error2[,..]]),e: |
8.7 真正的全捕捉
使用不带第一个参数的 except 语句将会捕捉所有类型的错误
这样的全捕捉是危险的:
- 它会捕捉
ctrl
+c
的用户指令 - 它会捕捉用
sys.exit
函数终止程序的企图
8.8 万事大吉
有些时候,在没有发生异常的时候执行一段语句是很有用的,像条件和循环那样增加一个 else 子句即可
8.9 最后……
- 最后,是 finally 子句,用来在可能的异常后进行清理,它和 try 子句联合使用
- 还可以在同一条语句中组合使用 try except else finally 或者其中3个
8.11 异常之禅
1 2 3 4 5 6 7 |
#以下是一个优秀的使用案例 def describePerson(person): pass try: 'Occupation:'+person['occupation'] except keyError:pass |
- 此处只应该使用pass的形式,否则前面的字符串将会被提前输出