美文网首页
python学习笔记-tip45(异常处理机制--错误处理)

python学习笔记-tip45(异常处理机制--错误处理)

作者: 黑键手记 | 来源:发表于2018-10-18 14:13 被阅读34次

    引言

    我们用什么语言写项目,其实都会出错,错误有很多种,有我们写的代码本身就有问题,这个时候属于编译错误,有的代码运行的时候有问题,这个属于运行时异常,python其实也有一套自己的异常处理机制。今天我们来学习一下。

    解决错误中的一种方式:返回错误码

    返回错误码其实是程序员排除错误的一种方式,他们往往会有一个错误码的字典,字典里面记录了什么数字对应着什么错误;然后当程序返回什么码的时候,去再对照之前那个字典,就能够知道什么错误了。
    但是错误码其实有一个局限性,就是当我们返回的结果如果和错误码混合在一起,那么久不太好区分了。

    为了避免这种问题,我们常用try catch finally(java语言中)等方式进行运行时异常的捕获。
    当然python也有类似的。

    try...except...finally

    我们先试用一下

        try:
            print('try...')
            r=10/0
            print('result:',r)
        except ZeroDivisionError as e:
            print('except:',e)
        finally:
            print('finally...')
        print('END')
    

    大家应该能看懂大概意思,我们来看下实际输出结果

    当我们认为某些代码可能会出错时,就可以用try来运行这段代码
    如果执行出错,则后续代码不会继续执行,而是直接跳转至except语句块
    执行完except后,如果有finally语句块,则执行finally语句块
    至此,执行完毕

    ok,当然,如果没有错误出现,那么也不会执行except代码块,如下如


    (注意:如果想得到整数,那么用"//")

    从上面的输出结果,可以看到,不论异常有没有finally一直都会执行,就像java中的一样

    那么,如果发生了不同种的错误,是不是可以使用多种except去处理呢?

    答案是肯定的!
    我们直接来看示例



    这个例子中,我们用一个 except 来捕获 ValueError ,一个 except 来捕获 ZeroDivisionError

    此外,如果没有错误发生的话,还可以在 except 后添加一个 else: 去执行没有该错误的处理

    如下面例子所示


    需要注意的是,并不是一个 except 对应一个 else ,而是当所有的 except 都没处理的话,才会执行唯一的 else ,下面的写法是错的

    错误写法

    Python的错误也是类,所以如果想捕获某一大类的错误,直接捕获大类就好了

    所有的错误类,都继承自 BaseException类

    常见的错误类型和继承关系看这里:
    https://docs.python.org/3/library/exceptions.html#exception-hierarchy

    使用try...except捕获错误还有一个巨大的好处,就是可以跨越多层调用

    请看下方示例:

    由此我们发现,有了这个跨越多层调用 except ,大大减少了复杂的 try except finally 代码的使用

    调用栈

    如果出的错没有处理,那么最终会被 python 解释器捕获,打印一个错误信息,然后程序退出
    我们来演示一下


    出错的时候,一定要分析错误的调用栈信息,才能定位错误的位置

    出了错之后要懂得找打错误的位置,上面的例子错误的位置就在第三行,10/s的位置,找到错误的位置,确定错误的类型,我们就能够解决了

    logging类

    我们从上面的例子知道了,即使我们不进行异常的捕获,python编译器也会对异常进行处理,我们也能定位到异常的位置,那么还要异常处理干什么?

    其实不然,python处理器虽然会处理异常,但是在处理的同时,也将程序终止。
    其实我们可以借助logging类去处理,logging类既会想python处理器一样将错误展示出来,也不会终止程序,如下例所示


    抛出错误

    需要明确的是:
    错误是一个 class ,我们捕获的错误其实就是捕获了该 class 的一个实例
    所以说,错误并不是凭空出现的,而是有意抛出的

    python内置的函数会抛出很多类型的错误,当然我们自己编写的函数也可以抛出错误。
    如果要抛出错误,我们可以根据需要,可以定义一个表示错误的 class ,然后选择好继承关系,
    最后用 raise 语句抛出一个错误的实例。

    比如,现在定义一个错误,让他继承ValueError

      class FooError(ValueError):
                pass
    

    然后在适当的地方抛出

      def  foo(s):
             if s==0:
                raise FooError('Foo Error %s' %s)
             return 10/s
    

    这样,当我们调用foo函数时,如果我们传入
    0
    那么将会抛出FooError的错误,并且打印
    “Foo Error 0”
    否则的话,则会直接返回 10/s 的返回值
    我们来看一下真实的案例演示:



    但是,我们只有在必要的时候才会定义我们自己的错误类型,在定义错误类型时,一定要继承对父类,否则会造成麻烦

    下面再来看另外一中处理错误的方式:重复抛出错误

    由上图,我们可以看出,虽然已经捕获了异常:打印出了FooError!
    但是又将之前的异常抛出,这是什么操作呢?

    这个操作有的时候很有必要

    有的情况下,由于当前函数不知道怎样去处理当前遇到的错误,那么最恰当的方式是往上抛,让顶层调用者去处理。就好比像一个员工遇到了一个棘手的问题不知道怎么处理,那么他最恰当的做法是交给他的上司,如果他的上司也处理不好,那么就会一直往上抛,直到抛给公司的大老板,让大老板去处理

    注意用法

    raise 如果直接写的话,那么就是把错误直接原封不动的抛给上级
    如果raise 后追加别的错误类型的话,其实就完成了把错误转化成另外一个类型额操作了,如

        try:
            10/s
        except ZeroDivisionError as e:    
             print('ZeroDivisionError')
             raise ValueError('ValueError')
    

    当然了,这种转化只要符合逻辑就可以,但是切忌瞎转化。

    相关文章

      网友评论

          本文标题:python学习笔记-tip45(异常处理机制--错误处理)

          本文链接:https://www.haomeiwen.com/subject/rarrzftx.html