异常的捕获和处理

一、异常处理

当我们的代码的某个地方发送能被解释器感知的错误(比如除以0的语句 a=4/0),这时候继续执行下面的代码就没有意义了,解释器这时会,中断当前代码的执行,并抛出一个异常对象,并在函数的调用栈从里到外,一层层的寻找出力该异常的代码,如果能找到就执行对应的代码,如果不能则会一直找到最外层的函数结束本次执行,异常的抛出和处理机制给了程序员通过异常处理代码的能力。

二、异常的产生

大家在学习课程的过程中,肯定遇到过执行代码出现问题的时候,通常你们会注意带一个Traceback这样的东西打印在屏幕上,像下面这样

这里,Traceback就是告诉我们程序执行有异常抛出了,异常就是最下面的这个NameError。它是异常对象的一种,上面的示例代码中没有什么函数调用,所以看不出来异常排出的轨迹,我们来看下面这个例子

def foo3():
    print("in f3")
    b = 4/0

def foo2():
    print('in f2')
    foo3()

def foo1():
    print('in f1')
    foo2()


foo1()

这里函数foo1会调用函数foo2,函数foo2会调用函数foo3。但是foo3里面有个明显的错误-分母为0,执行上面的代码,我们得到如下输入结果

D:\tools\Python37-32\python.exe E:/samples/test/tr.py
in f1
in f2
in f3
Traceback (most recent call last):
  File "E:/samples/test/tr.py", line 14, in <module>
    foo1()
  File "E:/samples/test/tr.py", line 11, in foo1
    foo2()
  File "E:/samples/test/tr.py", line 7, in foo2
    foo3()
  File "E:/samples/test/tr.py", line 3, in foo3
    b = 4/0
ZeroDivisionError: division by zero

这里解释器把整个异常抛出的路径给显示出来了。我们从上到下看,就是函数调用栈,直到出现错误的地方

三、异常的捕获和处理

3.1.异常的捕获处理

异常被抛出后,如果没有捕获处理,那么会导致当前程序的异常退出。而python通过try...except...finally...这样的方法来捕获和处理异常,看下面的代码

try:
    b=4/0
except  ZeroDivisionError
    print('handle ZeroDivisionError')

执行结果:

handle ZeroDivisonError

没有tracebark打印在屏幕上高速我们出错的信息了。因为除以0的异常被try...except捕获了。并执行了except里面的代码。而except后面跟着ZeroDivisionError是用

来指明它这段代码是要专门捕获ZeroDivisionError异常后执行

3.2.捕获多种异常

我们可以连接有好几个except代码段来分别捕获不同类型的异常,如下

try:
    ohmy
    b = 4/0
except ZeroDivisionError:
    print('handle ZeroDivisionError')
except NameError:
    print('handle NameError')

执行结果为:

handle NameError

由于执行到ohmy这句话就产生了异常,并且该异属于NameError类型,所以他被except NameErrot所捕获,执行了相应的代码。而except ZeroDivisionErrot不是对应的该异常类型,所以它对应的代码不会执行,如果没有异常产生,则except对应的语句块里面的代码不会被执行

3.3.获取异常对象

有的时候,我们在捕获异常的时候得到更具体的异常信息,会这样

try:
    ohmy
except NameError as e:
    print('hanle NameError:' e)

输出结果如下:

handle NameError:name 'ohmy' is not defined

上面的e就是异常对象本身,我们可以打印出异常对象里面存储的具体错误信息

3.4.捕获所有异常

有的时候,我们并不知道会抛出什么样的异常,但是我们并不希望有未知异常抛出的时候,程序被异常中止,这时候蜗牛可以捕获所以类型的异常,如下:

try:
    ohmy
except Exception as e:
    print('handle unkown exeption:' e)

执行结果如下:

handle unkown exeption:name 'ohmy is not defined'

也可以简单写出这样

try:
    ohmy
except:
    print('handle unkown exeption')

如果我们想看看异常抛出的详细调用栈的信息可以这样写

import traceback
try:
    ohmy
except:
    print('handle unkown exeption\n' + traceback.format_exc())

3.5.finally语句

有的时候,不管 是否有异常,我们都有执行一段代码,可以用关键字finally

try:
    ohmy
    b = 4/0
except ZeroDivisionError:
    print('handle ZeroDivisionError')
except NameError:
    print('handle NameError')
except:
    print('handle unkown exeption')
finally:
    print('in finally')

执行结果如下

D:\tools\Python37-32\python.exe E:/samples/test/tr.py
handle NameError
in finally

3.6.else语句

在 Python 中,还有另一种异常处理结构,就是 try except else 语句,也就是在原来 try except 语句的基础上再添加一个 else 子句,其作用是指定当 try 块中没有发现异常时要执行的代码。换句话说,当 try 块中发现异常,则 else 块中的语句将不会被执行。
例如如下程序:

s = input('请输入除数:')
try:
    result = 20 / int(s)
    print('20除以%s的结果是: %g' % (s , result))
except ValueError:
    print('值错误,您必须输入数值')
except ArithmeticError:
    print('算术错误,您不能输入0')
else:
    print('没有出现异常')
print("程序继续运行")

上面程序为异常处理流程添加了 else 块,当程序中的 try 块没有出现异常时,程序就会执行 else 块。运行上面程序,如果用户输入导致程序中的 try 块出现了异常,则运行结果如下:

请输入除数:a
值错误,您必须输入数值
程序继续运行

如果用户输入让程序中的 try 块顺利完成,则运行结果如下:

请输入除数:3
20 除以3 的结果是:6.66667
没有出现异常
程序继续运行

如果else和finally同时存在,则else需要在finally之前,顺序如下:

try:
    print("Try block")
except Exception as e:
    print("Except block")
else:
    print("Else block")
finally:
    print("Finally block")
posted @ 2019-07-31 16:10  酒剑仙*  阅读(288)  评论(0)    收藏  举报