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

引言

我们用什么语言写项目,其实都会出错,错误有很多种,有我们写的代码本身就有问题,这个时候属于编译错误,有的代码运行的时候有问题,这个属于运行时异常,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(异常处理机制--错误处理))