程序在执行过程中,经常会由于系统、或者用户输入等造成一些问题,我们称之为异常。
我们当然不能视而不见,或者当所有用户都是良好的用户,否则会造成意想不到严重后果。
今天我们就来学习对异常的处理。

python标准异常

python本身有一些内置的异常类型,就好像我们在编译我们的程序时,当我们出问题时会报错一样。
这些异常见下表:

异常名称

描述

BaseException

所有异常的基类

SystemExit

解释器请求退出

KeyboardInterrupt

用户中断执行(通常是输入^C)

Exception

常规错误的基类

StopIteration

迭代器没有更多的值

GeneratorExit

生成器(generator)发生异常来通知退出

StandardError

所有的内建标准异常的基类

ArithmeticError

所有数值计算错误的基类

FloatingPointError

浮点计算错误

OverflowError

数值运算超出最大限制

ZeroDivisionError

除(或取模)零 (所有数据类型)

AssertionError

断言语句失败

AttributeError

对象没有这个属性

EOFError

没有内建输入,到达EOF 标记

EnvironmentError

操作系统错误的基类

IOError

输入/输出操作失败

OSError

操作系统错误

WindowsError

系统调用失败

ImportError

导入模块/对象失败

LookupError

无效数据查询的基类

IndexError

序列中没有此索引(index)

KeyError

映射中没有这个键

MemoryError

内存溢出错误(对于Python 解释器不是致命的)

NameError

未声明/初始化对象 (没有属性)

UnboundLocalError

访问未初始化的本地变量

ReferenceError

弱引用(Weak reference)试图访问已经垃圾回收了的对象

RuntimeError

一般的运行时错误

NotImplementedError

尚未实现的方法

SyntaxError

Python 语法错误

IndentationError

缩进错误

TabError

Tab 和空格混用

SystemError

一般的解释器系统错误

TypeError

对类型无效的操作

ValueError

传入无效的参数

UnicodeError Unicode

相关的错误

UnicodeDecodeError

Unicode 解码时的错误

UnicodeEncodeError

Unicode 编码时错误

UnicodeTranslateError

Unicode 转换时错误

Warning

警告的基类

DeprecationWarning

关于被弃用的特征的警告

FutureWarning

关于构造将来语义会有改变的警告

OverflowWarning

旧的关于自动提升为长整型(long)的警告

PendingDeprecationWarning

关于特性将会被废弃的警告

RuntimeWarning

可疑的运行时行为(runtime behavior)的警告

SyntaxWarning

可疑的语法的警告

UserWarning

用户代码生成的警告

异常处理

try except else语句

先看格式:

try:

except AException:
else:

try后面跟着的,是我们要监控的语句,也就是说,我们预测这段代码可能会在运行起见出现错误。
except后面加的是异常的名字(或者说是异常的类型,这里我放的是一个A异常)。也就是说,如果这段我们监控的代码发生A异常时,就会执行这个except冒号后面对应的语句。
else则是用于没有任何错误发生的情况,也就是如果这段代码没有出现任何异常,那么就执行else后面的语句。
我们举个例子:

try:
a=10
b=input("请输入除数:")
print(a/float(b))
except ZeroDivisionError:
print("傻瓜,除数不能为0")
else:
print("一切正常")

当用户输入0时,我们的程序就可以从容地处理这个问题了。

不带任何异常类型的except

其实except的错误类型是可以缺省的(虽然不建议这么做),这样就会用同一段语句处理所有的错误,比如:

try:
a=10
b=input("请输入除数:")
print(a/float(b))
except:
print("你的输入有问题")
else:
print("一切正常")

这里我们就会统一处理这里的所有问题,比如上面一个例子,我们只会处理除数为0的情况,而这里我们也会处理用户输入一个非数字的字符串的情况。

带多个异常类型的except

既然except后面可以带一个异常或者不带,那能不能带多个呢?答案是肯定的。
我们可以在except后面加上多个异常,表示接下来的这些语句是用来处理这些异常的,也就是代码采用同一种方式应对这些异常。比如:

try:
a=10
b=input("请输入除数:")
print(a/float(b))
except (ZeroDivisionError,ValueError):
print("你的输入有问题")
else:
print("一切正常")

这样我们同样可以处理输入非数字字符串和除数为0的问题。

try-finally语句

我们知道,当发生某些严重错误时,我们的程序可能会要关闭,但是如果我们之前进行了某些特别的操作,比如新建一个文件流,这时如果我们不把这个文件流关闭的话,可能会造成缓冲区的数据丢失,所以我们应当在退出程序前关闭他们,而这就需要finally的帮助。
finally后面带的语句块无论是否发生异常都会执行:

try:
a=10
b=input("请输入除数:")
print(a/float(b))
except (ZeroDivisionError,ValueError):
print("你的输入有问题")
else:
print("一切正常")
finally:
print("关闭文件")

我们两次的运行结果如下:
请输入除数:2
5.0
一切正常
关闭文件

请输入除数:0
你的输入有问题
关闭文件

关闭文件的语句在每一次都执行了。

异常的参数

既然出了异常,当我们是直接用except或者except后面跟有多个异常时,我们应该怎么获取异常的信息从而知道是哪个异常呢?
我们可以用as来设置异常变量:

try:
a=10
b=input("请输入除数:")
print(a/float(b))
except (ZeroDivisionError,ValueError) as a:
print("你的输入有问题")
print(a)#打印异常信息
else:
print("一切正常")
finally:
print("关闭文件")
print("cgg")

主动触发异常

python中提供了主动抛出异常的方法,就是用raise
比如:

try:
a=10
b=input("请输入除数:")
if float(b)==0:
raise ZeroDivisionError
print(a/float(b))
except (ZeroDivisionError,ValueError) as a:
print("你的输入有问题")
print(a)
else:
print("一切正常")
finally:
print("关闭文件")
print("cgg")

但是这样可能看不出来差别,我们可以写个更简单但没啥用的例子:

try:
raise ValueError
except ValueError:
print("get Error")

这个例子更加明显和直接。
那么这有什么用呢?继续往下看。

自定义异常

我们在写代码时可以定义自己的异常,我们只需要自己写个类,然后继承Exception类即可,比如:

class cggError(Exception):
def __init__(self):
pass

然后我们可以试着抛出这个异常:

try:
raise cggError
except cggError:
print("cgg出错啦")

当然了,Exception是一个异常的基类,我们也可以继承其他的错误类比如:

class cggError(RuntimeError):
def __init__(self):
pass