什么是异常?
异常发生之后,异常之后的代码不再执行。异常就是程序运行时发生错误的信号,在python中,错误触发的异常如下:
python中异常的种类
常见的异常:
AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(的子类) ;代码没有正确对齐
IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError 试图访问字典里不存在的键
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
导致你以为正在访问它
ValueError 传入一个调用者不期望的值,即使值的类型是正确的
什么是异常处理?
程序员编写特定的代码,专门用来捕捉异常(这段代码与程序逻辑无关,只与处理异常有关)
当异常捕捉成功,进入异常处理分支,执行你为其定制的逻辑,使程序不会崩溃,这就是异常处理。
为什么要进行异常处理?
python解析器去执行程序,检测到一个错误时,触发异常,异常触发后,如果不被处理,程序就在当前异常处终止,后面的代码不会运行,没人会去运行一个突然崩溃的软件。
所以,必须提供一种异常处理机制来增强程序的健壮性与容错性。
如何进行异常处理?
python为每一种异常订制了一个类型,然后提供了一种特定的语法去处理异常
1.基本语法
try:
被检测的代码块
except 异常类型:
try中检测到异常,就执行此处的逻辑
例:dump存了4条记录,通过load一条一条的拿
import pickle
dic={(1,2,3):{'a','b'},1:'abc'}
dic1={(1,2,3):{'a','b'},2:'abc'}
dic2={(1,2,3):{'a','b'},3:'abc'}
dic3={(1,2,3):{'a','b'},4:'abc'}
with open('pickle_f','wb')as f:
pickle.dump(dic,f)
pickle.dump(dic1, f)
pickle.dump(dic2, f)
pickle.dump(dic3, f)
with open('pickle_f','rb')as f:
ret=pickle.load(f)
print(ret,type(ret))
ret = pickle.load(f)
print(ret, type(ret))
ret = pickle.load(f)
print(ret, type(ret))
ret = pickle.load(f)
print(ret, type(ret))
ret = pickle.load(f)
print(ret, type(ret))
当load超出写入的数据时,就会抛出EOFError异常,然后执行break
dic={(1,2,3):{'a','b'},1:'abc'}
dic1={(1,2,3):{'a','b'},2:'abc'}
dic2={(1,2,3):{'a','b'},3:'abc'}
dic3={(1,2,3):{'a','b'},4:'abc'}
with open('pickle_f','wb')as f:
pickle.dump(dic,f)
pickle.dump(dic1, f)
pickle.dump(dic2, f)
pickle.dump(dic3, f)
with open('pickle_f','rb')as f:
while True:
try:
ret=pickle.load(f)
print(ret,type(ret))
except EOFError:
break
注意:异常类只能用来处理指定的异常情况,如果出现非指定异常则无法处理。
# 未捕获到异常,程序直接报错
s1 = 'hello'
try:
int(s1)
except IndexError as e:
print e
2.多分支处理异常
如果你想要的效果是,对于不同的异常,定制不同的处理逻辑,就需要用到多分支。
l=['login','register']
for num,i in enumerate(l,1): #枚举:从1开始列举
print(num,i) #1 login 2 register
try:
num=int(input('num>>>')) #只能处理try-except之间代码的异常
print(l[num - 1])
except ValueError: #except处理的异常必须是和实际报错的异常相同
#从上往下报错的代码只要找到一个和报错类型相符的分支就执行这个分支中的代码,然后直接退出分支
print('请输入一个数字')
except IndexError:
#如果找不到能处理和报错类型相同的分支,会一直往下执行,到最后没找到就会报错
print('只能输入1或2')
3.多分支合并
l=['login','register']
for num,i in enumerate(l,1): #枚举:从1开始列举
print(num,i) #1 login 2 register
try:
num=int(input('num>>>')) #只能处理try-except之间代码的异常
print(l[num - 1])
except (ValueError,IndexError):
print('输入的内容不合法')
4.万能异常
万能异常永远只能放在所有异常处理代码的最后面。
try:
pass
except(ValueError,IndexError):
print('针对性处理')
except Exception as e:
print(e)
print('通用性处理')
实例:
def buy():
print('buy')
name #写几个异常
def back():
print('back')
[][1]
def show():
print('show')
1/0
def main():
l = [('购物',buy), ('退货',back),('查看订单',show)]
while True:
for num, i in enumerate(l, 1): # 枚举:从1开始列举
print(num, i[0])
num = int(input('num>>>'))
print(l[num - 1])
# 万能异常
try:
func = l[num - 1][1]
func()
except Exception:
print('用户在选择了%s操作后发生了不可知的异常'% l[num-1][0])
main()
4.1 如果你想要的效果是,无论出现什么异常,我们统一丢掉,或者使用同一段代码逻辑去处理他们,那么只需要 Exception就足够了。
s1 = 'hello'
try:
int(s1)
except Exception,e:
'丢弃或者执行其他逻辑'
print(e)
#如果你统一用Exception,没错,是可以捕捉所有异常,但意味着你在处理所有异常时都使用同一个逻辑去处理(这里说的逻辑即当前expect下面跟的代码块)
5.多分支+as语法:能将具体的错误打印出来
如果你想要的效果是,对于不同的异常,定制不同的处理逻辑,就需要用到多分支。
def buy():
print('buy')
name #在函数里写三个异常
def back():
print('back')
[][1]
def show():
print('show')
1/0
def main():
l = [('购物', buy), ('退货', back), ('查看订单', show)]
while True:
for num, i in enumerate(l, 1): # 枚举:从1开始列举
print(num, i[0])
num = int(input('num>>>'))
print(l[num - 1])
# 万能异常
try:
func = l[num - 1][1]
func()
except Exception as e:
print(e)
#可以打印出具体出错的行等信息
#print(e.args,e.__traceback__.tb_lineno,e.__traceback__.tb_frame)
print('用户在选择了%s操作后发生了不可知的异常' % l[num - 1][0])
main()
6.异常的其他机构
s1 = 'hello'
try:
int(s1)
except IndexError as e:
print(e)
except KeyError as e:
print(e)
except ValueError as e:
print(e)
#except Exception as e:
# print(e)
else:
print('try内代码块没有异常则执行我')
finally:
print('无论异常与否,都会执行该模块,通常是进行清理工作,比如:关闭文件')
7.主动触发异常
try:
raise TypeError('类型错误')
except Exception as e:
print(e)
8.自定义异常
class EvaException(BaseException):
def __init__(self,msg):
self.msg=msg
def __str__(self):
return self.msg
try:
raise EvaException('类型错误')
except EvaException as e:
print(e)
9.断言语法
断言相当于if语句,断言只能接收布尔值。
# assert 条件
assert 1 == 1 #True
assert 1 == 2 #False
try..except方式相较于if语句的好处
try...except异常处理机制就是取代if那种方式,让你的程序在不牺牲可读性的前提下增强健壮性和容错性。
异常处理中为每一个异常定制了异常类型(python中统一了类与类型,类型即类),对于同一种异常,一个except就可以捕捉到,可以同时处理多段代码的异常(无需写多个if判断式)减少了代码量,增强可读性。
try...except方式
- 把错误处理和真正的工作分开
- 代码更易组织,更清晰,复杂的工作任务更容易实现
- 毫无疑问,更安全了,不至于一些小的疏忽而使程序意外崩溃了
什么时候用异常处理?
try...except应该尽量少用,因为它本身就是你附加给你的程序的一种异常处理逻辑,与你的主要的工作没有半点关系,这种东西加多了会导致你的代码可读性变差,只有在有些异常无法预知的情况下,才应该加上try...except,其他的逻辑错误应该尽量去修正。