异常
在程序 运行 时,如果发生 错误 ,会阻止程序正常运行,就是 异常。
错误和异常的区别
错误
下面这两种错误,是人为造成的,那么就是错误
- 语法错误
- 逻辑错误
异常
异常也是错误,但与上述的错误不同。程序编写正确,是用户没正确操作导致的错误,即:在 运行 时发生 错误,像下面这些错误就是 异常
- 用户输入不合法的数据,如:执行
1/0 - 网络连接中断
- 打开不存在的文件
- 将文件保存到不存在的盘符
- 内存空间不够
异常的产生
像下面这种情况,执行报错,会抛出ZeroDivisionError异常,并且 后面的代码不会运行:
print("----欢迎使用除法计算器-----")
a = input("请输入被除数:")
b = input("请输入除数:")
a = float(a)
b = float(b)
res = a/b
print("除法结果:",res)
执行 8/4 可以正常运行
执行 9/0 报错如下:
ZeroDivisionError: division by zero
总结
不同的语言对错误处理并不一样,C语言中,用 函数返回值 表示 正确 或者 错误 ,处理起来不方便
高级语言都有异常处理机制,当出现错误时会 抛出异常
python也是如此。在python中, 异常也是类 , 都继承BaseException,当出现错误时会抛出 异常类对象,错误信息保存在异常类对象中
处理一个异常
语法
如果认为某些代码可能会出错时,就可以用try...except...来处理
语法格式如下:
try:
可能抛异常的代码
except 异常类 [as 异常对象]:
处理异常。如:打印错误信息
后续代码
as 异常对象可以省略
执行说明:
可能抛异常的代码不报错,except代码块忽略掉,直接执行后续代码可能抛异常的代码报错,就中止运行并抛出异常,根据抛出 异常 的 类型 ,找到与之相匹配的except 异常类,然后执行处理异常。
如果没有找到与之相匹配的except,就由python解释器处理,即:中止运行
例子1
print("----欢迎使用除法计算器-----")
a = input("请输入被除数:")
b = input("请输入除数:")
a = float(a)
b = float(b)
try:
print("1.进入 try 代码块")
res = a/b
print("除法结果:",res)
print("2.try代码块执行结束")
except ZeroDivisionError as e: # e是异常对象,封装异常的信息
print("3.进入 except 代码块")
print(e)
print("4.except代码块执行结束")
print("程序执行结束")
正常运行执行过程
输入 8、2,正常执行时,except 代码块不会执行,过程如下:
抛出异常执行过程
输入 8、0,抛出异常,异常类型与 except ZeroDivisionError 匹配,那么执行 except 代码块,然后继续运行后面的代码
处理异常
异常信息是英文提示,如下:
改为中文提示,修改 except 代码块,如下:
# print(e)
print("除数不能是0!")
省略 as e
如果不需要打印异常信息,可以省略as e,如下:
try:
i=1/0 #会抛异常
j=10 #抛异常后,不会运行此行代码
except ZeroDivisionError:
print('0不能是被除数')
s='hello world'
例子2
try:
i=1/0 #会抛异常
j=10 #抛异常后,不会运行此行代码
except TypeError as e:
print('except:',e)#抛异常后会执行此行代码
s='hello world'
抛出异常,异常类型与except TypeError 不匹配,就由python解释器处理,即中止运行
例子3
将 例子1 改造成函数
def test(i,j):
try:
r=i/j
return r
except ZeroDivisionError as e:
print('except:',e)#抛异常后会执行此行代码
print('捕捉ZeroDivisionError异常时,本行文字才会打印')
调用执行:
#正常运行
a=test(1,1)
print(a+5)
#当传入0时,抛ZeroDivisionError异常,并会处理异常
a=test(1,0)
print(a+5)
'''
当传入字符串时,报TypeError错误,except代码块中没有捕捉这个异常,所以不会处理,而是直接抛出
'''
a=test(1,'0')
print(a+5)
缺点
无法处理多个错误
处理多个异常
为了解决上面例子的问题,需要用多个 except 代码块处理不同的异常
语法
try:
可能抛异常的代码
except 异常类1 [as 异常对象1]:
处理异常1。如:打印错误信息
except 异常类2 [as 异常对象2]:
处理异常2。如:打印错误信息
......
后续代码
例子4
完善例子3
将 例子1 改造成函数
def test(i,j):
try:
r=i/j
return r
except ZeroDivisionError as e:
print('except:',e)
except TypeError as e:
print('except:',e)
print('捕捉ZeroDivisionError异常时,本行文字才会打印')
调用执行:
#正常运行
a=test(1,1)
print(a+5)
#当传入0时,抛ZeroDivisionError异常,并会处理异常
a=test(1,0)
print(a+5)
#当传入字符串时,抛TypeError异常,并会处理异常
a=test(1,'0')
print(a+5)
缺点
这种处理错误的方法,会出现bug:报错后,只是打印错误信息,导致上层程序不知道运行是否正确,特别是返回值为None,无法继续运算。
注意:
很多时候,不要只是 打印异常信息,如果不知道怎么处理错误,就 抛出异常
处理异常的顺序
在python中,异常也是类,都继承BaseException,在使用except时要注意,不但捕获该类型的错误,也会 处理其子类类型的异常
内置异常类说明:
http://www.malaoshi.top/show_1EF2I6EXS38I.html
将上面的代码改造
def test(i,j):
try:
r=i/j
return r
except BaseException as e:
print('都被父类异常捕捉,except:',e)
except ZeroDivisionError as e2:
print('被除数不能是0')
except TypeError as e3:
print('只能传入int和float')
print('报错时才会打印本行文字')
调用执行
a=test(1,1)
print(a)
print(a+5)
a=test(1,0)
print(a)
print(a+5)
a=test(1,'1')
print(a)
print(a+5)
注意:
第一个except BaseException as e:代码块的异常类是BaseException,会捕获到所有异常错误,导致后面的except代码块都失效了
所以要将 子类异常写在上面 ,父类异常写在下面
finally关键字
有两种写法,一种是try...except...finally...,一种是try...finally...
语法1
try:
可能抛异常的代码
except 异常类 as 异常对象:
处理异常,如:打印错误信息
finally:
一定会执行的代码
执行顺序:
try代码块中不抛异常,正常执行try代码块,然后执行finally代码块try代码块抛异常,中止运行try代码块,如果异常类型与except 异常类相匹配,就执行except代码块,然后执行finally代码块- 如果异常类型与
except 异常类都不匹配,就执行finally代码块,最后由python解释器处理异常
注意:
不论是否抛异常,不论except代码块是否执行,一定执行 finally代码块
应用场景
一般用于清理、回收等操作。
在读写文件时,读写文件不论是否抛出异常,读写后都应该 释放 文件对象,那么就将 释放文件对象 的操作放入 finally 代码块中。
操作数据库也是如此。
语法2
except可以省略
try:
可能抛异常的代码
finally:
一定会执行的代码
执行顺序:
try代码块中不抛异常,正常执行try代码块,然后执行finally代码块try代码块抛异常,中止运行try代码块,然后执行finally代码块,最后由python解释器处理异常
例子5-语法1
path = input("请输入要读取的文件路径:")
try:
f = open(path,'r',encoding='utf-8')
print(f.read())
f.close()
except FileNotFoundError as e:
# print(e)
print("读取失败,文件不存在:",path)
print("程序执行结束")
打开存在文件时
输入存在文件时,能够正常运行
打开不存在文件时
输入不存在文件路径时,会报错,如下:
改进1
加上 finally 代码块,将 关闭文件代码 写在该代码块中
path = input("请输入要读取的文件路径:")
try:
f = open(path,'r',encoding='utf-8')
print(f.read())
except FileNotFoundError as e:
# print(e)
print("读取失败,文件不存在:",path)
finally: # 永远都会执行
print("1.进入finally代码块")
f.close()
print("2.finally代码块执行结束")
print("程序执行结束")
打开存在文件时
正常运行时,会执行 finally 代码块
打开不存在文件时
打开不存在文件时,先执行 except 代码块,然后执行 finally 代码块,但会报错,如下图:
改进2
path = input("请输入要读取的文件路径:")
f = None
try:
f = open(path,'r',encoding='utf-8')
print(f.read())
except FileNotFoundError as e:
# print(e)
print("读取失败,文件不存在:",path)
finally: # 永远都会执行
print("1.进入finally代码块")
if f:
f.close()
print("2.finally代码块执行结束")
print("程序执行结束")
总结
如果有 finally,那么一定会执行 finally 代码块,即使在 try 中 return 结果,也会执行finally 代码块
例子6-语法2
def test(i,j):
try:
r=i/j
return r
finally:
print('finally代码块')
print('捕捉ZeroDivisionError异常时,本行文字才会打印')
test(1,'2')
else关键字
语法
try:
可能抛异常的代码
except 异常类 as 异常对象:
处理异常,如:打印错误信息
else:
没有异常时执行
finally:
一定会执行的代码
执行顺序:
当try代码块没有抛异常时,就会执行else代码块
注意:return语句不要写在try代码块中,否则不会执行eles代码块
例子7
def test2(i,j):
try:
r=i/j
except ZeroDivisionError as e:
print('except:',e)#抛异常后会执行此行代码
else:
print('没有异常')
finally:
print('finally代码块')
print('捕捉ZeroDivisionError异常时,本行文字才会打印')
return r
print(test2(1,2))
注意:
return 语句不要写在 try 代码块中,否则不会执行 eles 代码块
raise抛出异常
一般用在函数中,比如登录,当登录失败时,就抛出异常,由外部程序处理异常
def login(username,password):
if username == 'lilei' and password == '123456':
return True
else:
raise Exception('用户名或密码错误!')
username = input("请输入用户名:")
password = input("请输入密码:")
try:
res = login(username,password)
if(res):
print("登录成功!")
except Exception as e:
print(e)
感谢链接:
http://www.runoob.com/python/python-exceptions.html




