一、异常简介
1、一个异常的例子
当如下的Python程序在运行时检测到一个错误,一般这时候解释器就无法继续执行代码了,会出现一些错误的提示,这就是所谓的"异常"。
#! /usr/bin/python3
print('========1========')
open('123.txt','r')
print('========2========')
出现错误:
================
Traceback (most recent call last):
File "./8try.py", line 4, in <module>
open('123.txt','r')
FileNotFoundError: [Errno 2] No such file or directory: '123.txt'
例如:读取一个不存在的文件或者用一个数除以0等错误都属于异常。
比较常见的异常类型如下:
AttributeError 试图访问一个对象没有的属性,比如foo.x,但是foo没有属性x
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(的子类) ;代码没有正确对齐
IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError 试图访问字典里不存在的键
KeyboardInterrupt Ctrl+C被按下
NameError 尝试访问一个没有申明的变量
SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,导致你以为正在访问它
ValueError 传入一个调用者不期望的值,即使值的类型是正确的
2、try...except捕获单个异常
把可能出现问题的代码,放在try中,把处理异常的代码,放在except中,修改代码成如下所示:
#! /usr/bin/python3
try:
print('========1========')
open('123.txt','r')
print('========2========')
except IOError:
print('========3========')
执行结果:
========1========
========3========
可以看出:其实代码执行到open函数是没有继续执行下去,然后执行到了处理异常的代码中了,这样至少代码不会中断了
3、try...except捕获多个异常
#! /usr/bin/python3
try:
print('========1========')
# open('123.txt','r')
print('========2========')
print(num)
print('========3========')
except (NameError, IOError):
print('========4========')
运行结果如下:
========1========
========2========
========4========
关键词:多个异常时候,使用元组将它们组合起来
4、使用as获取捕获到的异常的基本信息
#! /usr/bin/python3
try:
print('========1========')
# open('123.txt','r')
print('========2========')
print(num)
print('========3========')
except (NameError, IOError) as result:
print(result)
运行结果:
========1========
========2========
name 'num' is not defined
5、在try...except...中没有捕获到异常,那么就执行else中的代码
#! /usr/bin/python3
num = 100
try:
print('========1========')
# open('123.txt','r')
print('========2========')
print(num)
print('========3========')
except (NameError, IOError) as result:
print(result)
else:
print('=====NO ERROR======')
执行结果:
========1========
========2========
100
========3========
=====NO ERROR======
6、在try...except...中不管有没有捕获到异常,都执行finally中的代码
无异常的代码:
#! /usr/bin/python3
num = 100
try:
print('========1========')
# open('123.txt','r')
print('========2========')
print(num)
print('========3========')
except (NameError, IOError) as result:
print(result)
else:
print('=====NO ERROR======')
finally:
print('======Forever=====')
有异常的代码:
#! /usr/bin/python3
#num = 100
try:
print('========1========')
# open('123.txt','r')
print('========2========')
print(num)
print('========3========')
except (NameError, IOError) as result:
print(result)
else:
print('=====NO ERROR======')
finally:
print('======Forever=====')
执行结果都是
======Forever=====
二、异常的传递
主要是在函数嵌套和try...except嵌套中传递
#! /usr/bin/python3
def test1():
print("----test1-1----")
print(num)
print("----test1-2----")
def test2():
print("----test2-1----")
test1()
print("----test2-2----")
def test3():
try:
print("----test3-1----")
test1()
print("----test3-2----")
except Exception as result:
print("捕获到了异常,信息是:%s"%result)
print("----test3-2----")
test3()
print("------华丽的分割线-----")
test2()
- 如果try嵌套,那么如果里面的try没有捕获到这个异常,那么外面的try会接收到这个异常,然后进行处理,如果外边的try依然没有捕获到,那么再进行传递。。。
- 如果一个异常是在一个函数中产生的,例如函数A---->函数B---->函数C,而异常是在函数C中产生的,那么如果函数C中没有对这个异常进行处理,那么这个异常会传递到函数B中,如果函数B有异常处理那么就会按照函数B的处理方式进行执行;如果函数B也没有异常处理,那么这个异常会继续传递,以此类推。如果所有的函数都没有处理,那么此时就会进行异常的默认处理,即通常见到的那样
- 注意观察上图中,当调用test3函数时,在test1函数内部产生了异常,此异常被传递到test3函数中完成了异常处理,而当异常处理完后,并没有返回到函数test1中进行执行,而是在函数test3中继续执行
三、自定义异常并抛出(raise)
你可以用raise语句来引发一个异常。异常/错误对象必须有一个名字,且它们应是Error或Exception类的子类.
#! /usr/bin/python3
class ShortInputException(Exception):
'''自定义的异常类'''
def __init__(self, length, atleast):
#super().__init__()
self.length = length
self.atleast = atleast
def main():
try:
s = input('请输入 --> ')
if len(s) < 3:
# raise引发一个你定义的异常
raise ShortInputException(len(s), 3)
except ShortInputException as result:#x这个变量被绑定到了错误的实例
print('ShortInputException: 输入的长度是 %d,长度至少应是 %d'% (result.length, result.atleast))
else:
print('没有异常发生.')
main()
运行结果:
linbo@linbo-virtual-machine:~/python/python1$ ./9raise.py
请输入 --> 12
ShortInputException: 输入的长度是 2,长度至少应是 3
四、在异常中抛出异常
有时候,捕获到了异常但是不想去处理这个异常,重新抛出去让另一层的异常处理函数去处理,示例代码如下:
#! /usr/bin/python3
class Test(object):
def __init__(self, switch):
self.switch = switch #开关
def calc(self, a, b):
try:
return a/b
except Exception as result:
if self.switch:
print("捕获开启,已经捕获到了异常,信息如下:")
print(result)
else:
#重新抛出这个异常,此时就不会被这个异常处理给捕获到,从而触发默>认的异常处理
raise
a = Test(True)
a.calc(11,0)
print("----------------------华丽的分割线----------------")
a.switch = False
a.calc(11,0)
运行结果如下:
捕获开启,已经捕获到了异常,信息如下:
division by zero
----------------------华丽的分割线----------------
Traceback (most recent call last):
File "./9raise.py", line 24, in <module>
a.calc(11,0)
File "./9raise.py", line 8, in calc
return a/b
ZeroDivisionError: division by zero
关键词:上面程序使用switch打开与关闭处理异常,在关闭异常处理时,捕获到之后直接又抛出了。 |