Python提供了两个非常重要的功能来处理异常和错误:
1) 异常处理try….except
2) 断言assert
异常和断言,可以用于我们调试python程序,跟踪程序执行状态,尽快排查问题。
35.1 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 |
用户代码生成的警告 |
35.2 什么是异常
去写一个只读文件,将会出现IO异常——IOError。
什么是异常?
异常是指在程序的运行过程中,某处程序执行发生了意外情况,出错情况,是一个事件。该事件会在程序执行过程中发生,并影响程序的正常运行。
一般python在无法处理程序执行过程中的问题时,就会抛出一个异常,我们要想办法去捕获这个异常,掌握程序执行的一个状态。
35.3 异常如何处理
Python中通过try/except语句来捕获异常;
语法格式如下:
try:
<语句> #相关代码,可以是多条
except<名字>:#名字即异常的名称,比如IO操作异常就叫IOError
<语句> #如果异常捕获到,这里的语句将会执行,可以有多条语句
except<名字>,<数据>:
<语句> #如果引发了‘name‘异常,获得附加的数据
else:
<语句> #如果没有捕获到异常,则会执行这条语句,可以有多条语句
实例如下:
35.4 SystemExit方法
SystemExit方法,表示解释器请求退出,这是什么意思呢。我们来看实例分析!
如果我们在第6行判断到了异常,此时没有必要执行第9行及后面的代码,所以我们需要在第6行后退出进程。
代码如下:
再来看下面的程序
那么SystemExit和sys.exit到底什么区别呢?
35.5 SystemExit和sys.exit的区别
SystemExit是一个异常捕获类型,我们可以通过try….except来捕获sys.exit这个异常。
注意try….except嵌套的情况。
35.6 ctrl+c和KeyboardInterrupt异常
程序每隔1秒打印一个*号,如果碰到ctrl+c则退出。
因为pycharm不能检测ctrl+c快捷键,所以在ubuntu的python2.7上做的实验
注意在pycharm中,print函数去掉换行符是print(“*”,end=””)
怎么捕获KeyboardInterrupt呢?
注意1,上面那个程序,当捕获到ctrl+c的时候,异常处理仅仅是一个打印语句。
注意2,else语句分支可不要。
思考:为什么捕获到ctrl+c信号,程序退出了呢,而不像sys.exit函数,捕获它不会退出进程?
35.7 KeyboardInterrupt和SystemExit异常的理解
我们在35.4和35.5的实验中,看到如果我们用try…except System.Exit来捕获sys.exit函数,那么sys.exit不会退出当前进程。而如果我们不去捕获这个信号(sys.exit执行会产生SystemExit信号)。
但是,我们在捕获ctrl+c信号的时候,ctrl+c信号即使被try….except KeyboardInterrupt捕获到,还是照常终止。也就是说,ctrl+c信号不会受try。。。except影响。
最后总结:
Sys.exit如果被try捕获到,函数本身不会生效;
Ctrl+c如果被try捕获到,函数本身会生效。
35.8 使用except而不带异常类型
有时候我们在使用
Try:
<语句>
Except[异常类型]:
<语句>
的时候,我们不记得具体的异常类型名称(那么多类型名称很难记住,而且有些还不一定完全知道他的意思),此时怎么办呢?
其实,我们可以在except后面不带具体的异常类型,如:
因为忘记导入time模块,在使用time.sleep(1)的时候发生异常,此时我们没有去捕获具体的异常,而是笼统的,所以第10行语句执行,我们也不知道具体是什么异常。
我们再把这个程序改为正常情况!
注意1,import可以同时导入多个模块,如第3行;
注意2:第8行是为了刷新行缓存;
35.9 except带多种类型的异常
我们不知道是哪个异常,我们试着过滤,一个个去掉
注意:第12行并没有执行,因为我们捕获的是RuntimeError异常,而第8行发生的异常是NameError。
Except带多种类型异常的另一种表示方式:
这种格式会比较好!
35.10 try…finally句型
Try:
<语句>
Except[异常类型]:
<语句>
Finally:
<语句> #这条语句会无条件执行
Else:
<语句>
Finally下面的语句第16行会执行。有人会问:如果在第12行,判断到异常后退出进程,finally也会执行吗?
我们试试:
难道是finally会造成sys.exit没有生效吗?
我们再去掉finally
我们发现,去掉finally后,sys.exit会生效(退出进程)。
结论:finally会让进程终止的代码,比如sys.exit执行失效。
注意:finall和else不能同时出现!
35.11 异常的参数
例一:
#------异常带参数的情况-----
#-*-coding:utf8-*-
try:
fobj = open("readme.txt")
fobj.write("1234567890")
except IOError as info:
print("异常发生:" ,info.args,info.errno,info.filename,info.__doc__)
else:
print("没有异常发生....")
#---------输出结果------------
C:\Users\xiajiashan\AppData\Local\Programs\Python\Python36-32\python.exeG:/somy/python/pycharm/Exception/except_argment.py
异常发生: (‘not writable‘,)None None None
Process finished withexit code 0
Except IOErroras info:这条语句,将会把异常产生的信息放在info中。包括参数本身info.args,错误号info.errno,文件名info.filename等。
例二:
#------异常带参数的情况-----
#-*-coding:utf8-*-
try:
fobj = open("abc.txt")
fobj.write("1234567890")
except IOError as info:
print("异常发生:" ,info.args,info.errno,info.filename,info.__doc__)
else:
print("没有异常发生....")
运行结果:
C:\Users\xiajiashan\AppData\Local\Programs\Python\Python36-32\python.exeG:/somy/python/pycharm/Exception/except_argment.py
异常发生: (2, ‘No such fileor directory‘) 2 abc.txt File not found.
Process finished withexit code 0
2表示错误号info.errno
注意:到了python3.x后,不能这样写
#------异常带参数的情况-----
#-*-coding:utf8-*-
try:
fobj = open("readme.t
fobj.write("123456789
except IOError,info:
print("异常发生:" ,info.a
else:
print("没有异常发生....")
将会出现下面编译错误:
C:\Users\xiajiashan\AppData\Local\Programs\Python\Python36-32\python.exeG:/somy/python/pycharm/Exception/except_argment.py
File"G:/somy/python/pycharm/Exception/except_argment.py", line 6
except IOError,info:
^
SyntaxError: invalidsyntax
Process finished withexit code 1
35.12 触发异常
Python中,可以通过使用raise触发一个异常,以便通过try。。。except捕获。
语法如下:
Try:
<语句>
Raise Exception #Exception是标准异常名称,比如NameError
Except Exception: #注意这里的Exception也是一个异常名称
<语句>
Else:
<语句>
我们来看实例:
当打印到第10个*号的时候,我们自己触发了一个NameError异常,所以接下来的10个*号不会打印;
因为异常被捕获到了——第15行会执行。
注意:第11行不能有冒号;而且raise后面的异常必须是标准异常;
35.13 自定义异常
自定义异常需要到学了类之后再讲。