异常处理结构、代码测试与调试
异常处理结构
Python内置异常层次结构
BaseException是所有内置异常类的基类
常见异常处理结构形式
1.try…except…
try子句中的代码块包含可能引发异常的语句
except子句用来捕捉相应的异常
try:
#可能会引发异常的代码,先执行一下试试
except Exception [as reason]:
#如果try中的代码抛出异常并被except捕捉,就执行这里的代码
while True:
x=input('please input:')
try:
x=int(x)
print('You have input{0}'.format(x))
break
except Exception as e:
print('Error')
2.try…except…else…
带有else子句的异常处理结构可以看作是一种特殊的选择结构。
try:
#可能会引发异常的代码
except Exception [as reason]:
#用来处理异常的代码
else:
#如果try子句中的代码没有引发异常,就继续执行这里的代码
while True:
x=input('Please input:')
try:
x=int(x)
except Exception as e:
print('Error!.')
else:
print('You have input{0}'.format(x))
break
3.try…except…finally
在这种结构中,无论try中的代码是否发生异常,也不管抛出的异常有没有被except语句捕获,finally子句中的代码总是会得到执行。
try:
#可能会引发异常的代码
except Exception [as reason]:
#处理异常的代码
finally:
#无论try子句中的代码是否引发异常,都会执行这里的代码
def div(a,b):
try:
print(a/b)
except ZeroDivisionError:
print('The second parameter cannot be 0.')
finally:
print(-1)
div(3,5)
div(3,0)
0.6
-1
The second parameter cannot be 0.
-1
如果try子句中的异常没有被except语句捕捉和处理,或者except子句或else子句中的代码抛出了异常,那么这些异常将会在finally子句执行完后再次抛出。
def div(a,b):
try:
print(a/b)
except ZeroDivisionError:
print('The second parameter cannot be 0.')
finally:
print(-1)
div('3',5)
finally子句中的代码也可能会引发异常。下面代码的本意是使用异常处理结构来避免文件对象没有关闭的情况发生,但是由于指定的文件不存在而导致打开失效,结果在finally子句中关闭文件时引发了异常。
try:
f1=open('test1.txt','r') #文件不存在,抛出异常,不会创建文件对象f1
line=f1.readline() #后面的代码不会被执行
print(line)
except SyntaxError: #这个except并不能捕捉上面的异常
print('Sth wrong')
finally:
f1.close() #f1不存在,再次引发异常
如果在函数中使用异常处理结构,尽量不要在finally子句中使用return 语句,以免发生非常难以发现的逻辑错误。
例如下面的代码,不管参数是否符合函数要求,调用函数时都得到了同样的错误信息。
def div(a,b):
try:
return a/b
except ZeroDivisionError:
return 'The second parameter cannot be 0.'
finally:
return 'Error'
print(div(3,5))
Error
4.可以捕捉多种异常的异常处理结构
在实际开发中,同一段代码可能会抛出多种异常,并且需要针对不同的异常类型进行相应的处理。为了支持多种异常的捕捉和处理,Python提供了带有多个except的异常处理结构,一旦某个except捕捉到了异常,则其他的except子句将不会再尝试捕捉异常。
try:
#可能会引发异常的代码
except Exception1:
#处理异常类型1的代码
except Exception2:
#处理异常类型2的代码
except Exception3:
#处理异常类型3的代码
下面的代码演示了这种异常处理结构的用法,连续运行了3次并输入不同的数据,结果如下:
try:
x=float(input('请输入被除数:'))
y=float(input('请输入除数:'))
z=x/y
except ZeroDivisionError:
print('除数不能为0')
except TypeError:
print('被除数和除数应为数值类型')
except NameError:
print('变量不存在')
else:
print(x,'/',y,'=',z)
请输入被除数: 30
请输入除数:5
30.0 / 5.0 = 6.0
请输入被除数:30
请输入除数:0
除数不能为0
在实际开发中,有时候可能会为几种不同的异常设计相同的异常处理代码(虽然这种情况很少)。为了减少代码量,Python允许把多个异常类型放到一个元组中,然后使用一个except子句捕捉多种异常,并且共用同一段异常处理代码。
try:
x=float(input('请输入被除数:'))
y=float(input('请输入除数:'))
z=x/y
except (ZeroDivisionError,TypeError,NameError):
print('捕捉到了异常')
else:
print(x,'/',y,'=',z)
请输入被除数: 30
请输入除数:0
捕捉到了异常
5.同时包含else子句、finally子句和多个except子句的异常处理结构
Python异常处理结构中可以同时包含多个except子句、else子句和finally子句
例如:
def div(x,y):
try:
print(x/y)
except ZeroDivisionError:
print('ZeroDivisionError')
except TypeError:
print('TypeError')
else:
print('No Error')
finally:
print("executing finally clause")
div(3,5)
div('3',5)
0.6
No Error
executing finally clause
TypeError
executing finally clause