• python 错误捕获机制分析


    python语言是编程中使用率在Top 3之内的语言。python语言以灵活与简单著称,那么越是灵活的语言越需要判断出错的功力。

    简单示例

    以下是一个简单的错误程序,被除数不可为0,那么看看该代码的执行。

    a = 10 
    
    b = 0
    
    c = a / b
    
    print c 

    出错报告是:在文件error_three.py 的第5行 c = a / b报错,原因是整数除法或者取模运算的被除数为0

    解释异常被捕获的流程:当程序运行到 c = a / b时,有异常产生,然后python解释器就捕获了该异常,并判断异常的类型,最后将该异常抛出,终止了程序的运行

    python的异常捕获原则是这样的:程序某一行产生异常,解释器会一层层的上报,寻找异常的捕获代码。如果解释一直上报到main()函数中都没有捕获异常的语句,那么main()函数会捕获到异常,并抛出异常。

     

    下面看一个复杂一点的函数异常处理:

     1 #coding:utf-8
     2 
     3 def get_num():
     4     num = int(input("input you num:"))
    return num
    5 6 def fun_two(): 7 num = get_num() 8 div = 10 -num 9 return div 10 11 def fun_three(): 12 two_num = fun_two() 13 three_num = 10 / two_num 14 print three_num 15 16 17 if __name__ == '__main__': 18 fun_three()

    这里产生异常的点有两个:

    1、被除数为0,在13行

    2、输入类型错误在4行

     

    首先我们看第一个异常:

    输入10,div = 10 - 10 = 0,three_num = 10 / 0,然后报错。

    具体分析报错信息,从上到下:

    1、错误出现在文件error_two.py中的19行,出错函数:fun_three

    2、在fun_three中的14行,代码:three_num = 10 / two_num中报错,原因是:被除数不能为0。

    按照python解释器的工作原理:程序在14行出错,然后一层层上报到main函数,main函数从上到下找到出错点。下面看看第二个错误是不是也符合这个规律。

    出错解释:

    1、程序在19行出错,出错函数是:fun_three

    2、fun_three内部在13行出错,出错代码是函数:two_num = fun_two()

    3、fun_two内部在8行出错,出错代码是函数:num = get_num()

    4、get_num函数在第4行出错,出错代码是:num = int(input("input you num:")) 。出错原因是:类型错误,int()函数不能转化非数字类型的函数

     

    从以上的分析来看,我们按照一个规律肯定能找到程序出错的地方和原因。但是光找到出错的地方还不够,还要能够自动的处理这些错误。程序要达到的效果是坚决不出错误,万一出了错误也要能够自动的捕获错误,记录下来。本着个原则,我们看看在python中是如果主动捕获错误的。

     

    以第一个简单的程序为例,报错如下:

     错误的确是显示出来了,但是程序也停止了。这里有三点要求没有达到:

    1、程序终止了,后面如果还有重要代码也无法执行了

    2、程序是给大众使用的,程序员肯定能看懂错误原因,但是普通人就不好说了。错误提示没有

    3、程序出错也没有错误日志记录,当然前提是需要的话

    捕获异常

    那么给这个简单的小程序加一个异常捕获的代码:

     1 #coding:utf-8
     2 a = 10 
     3 
     4 b = 0
     5 try:
     6     c = a / b
     7 except:
     8     print "程序出现了异常"
     9 else:
    10     print c

    再次执行看看:

    这样异常就被except捕获到了。并且捕获到之后打印出except中的提示信息。

    python中标准的程序异常捕获语句是:

    try
        可能出错的语句
    except:
        捕获到的异常

    一直提到异常,前面我们也见过了两个异常,分别是:TypeError和ZeroDivisionError,这两个异常说的是类型异常和被除数为0。聪明的读者你肯定想到python已经定了常见的,大量的异常类型。是的,具体来说python定义的异常有如下:

     1 BaseException
     2  +-- SystemExit
     3  +-- KeyboardInterrupt
     4  +-- GeneratorExit
     5  +-- Exception
     6       +-- StopIteration
     7       +-- StopAsyncIteration
     8       +-- ArithmeticError
     9       |    +-- FloatingPointError
    10       |    +-- OverflowError
    11       |    +-- ZeroDivisionError
    12       +-- AssertionError
    13       +-- AttributeError
    14       +-- BufferError
    15       +-- EOFError
    16       +-- ImportError
    17            +-- ModuleNotFoundError
    18       +-- LookupError
    19       |    +-- IndexError
    20       |    +-- KeyError
    21       +-- MemoryError
    22       +-- NameError
    23       |    +-- UnboundLocalError
    24       +-- OSError
    25       |    +-- BlockingIOError
    26       |    +-- ChildProcessError
    27       |    +-- ConnectionError
    28       |    |    +-- BrokenPipeError
    29       |    |    +-- ConnectionAbortedError
    30       |    |    +-- ConnectionRefusedError
    31       |    |    +-- ConnectionResetError
    32       |    +-- FileExistsError
    33       |    +-- FileNotFoundError
    34       |    +-- InterruptedError
    35       |    +-- IsADirectoryError
    36       |    +-- NotADirectoryError
    37       |    +-- PermissionError
    38       |    +-- ProcessLookupError
    39       |    +-- TimeoutError
    40       +-- ReferenceError
    41       +-- RuntimeError
    42       |    +-- NotImplementedError
    43       |    +-- RecursionError
    44       +-- SyntaxError
    45       |    +-- IndentationError
    46       |         +-- TabError
    47       +-- SystemError
    48       +-- TypeError
    49       +-- ValueError
    50       |    +-- UnicodeError
    51       |         +-- UnicodeDecodeError
    52       |         +-- UnicodeEncodeError
    53       |         +-- UnicodeTranslateError
    54       +-- Warning
    55            +-- DeprecationWarning
    56            +-- PendingDeprecationWarning
    57            +-- RuntimeWarning
    58            +-- SyntaxWarning
    59            +-- UserWarning
    60            +-- FutureWarning
    61            +-- ImportWarning
    62            +-- UnicodeWarning
    63            +-- BytesWarning
    64            +-- ResourceWarning

    常见的异常类型如下:

    AttributeError:属性错误,特性引用和赋值失败时会引发属性错误

    NameError:试图访问的变量名不存在

    SyntaxError:语法错误,代码形式错误

    Exception:所有异常的基类,因为所有python异常类都是基类Exception的其中一员,异常都是从基类Exception继承的,并且都在exceptions python 模块中定义。

    IOError:python ioerror,一般常见于打开不存在文件时会引发IOError错误,也可以解理为输出输入错误

    KeyError:使用了映射中不存在的关键字(键)时引发的关键字错误

    IndexError:索引错误,使用的索引不存在,常索引超出序列范围

    TypeError:类型错误,内建操作或是函数应于在了错误类型的对象时会引发类型错误

    ZeroDivisonError:除数为0,在用除法操作时,第二个参数为0时引发了该错误

    ValueError:值错误,传给对象的参数类型不正确,像是给int()函数传入了字符串数据类型的参数。

    标准异常捕获 

    在上面的处理函数中我都是用异常的基类去捕获异常的。这样做有一个不好的地方就是我们虽然能捕获异常,但是不能看出是哪一个异常。使用更精确的异常捕获类型能够精确找到出错点。

     1 #coding:utf-8
     2 
     3 def get_num():
     4     try:
     5         num = int(input("input you num:"))
     6    except TypeError,e:
     7         print e
     8 
     9 def fun_two():
    10     num = get_num()
    11     div = 10 -num
    12     return div
    13 
    14 def fun_three():
    15     two_num = fun_two()
    16     three_num = 10 / two_num 
    17     print three_num
    18 
    19 
    20 if __name__ == '__main__':
    21     fun_three()

    怎么还是报错了,不是捕获了异常了吗?这里要看清楚,我是在输入的时候捕获的异常,并且异常也捕获到了,看前两行的输出信息:int()函数的参数一定要是一个字符串或者数字,不能使type类型。按照之前的规律去分析一下这里的报错在哪里。

    1、报错在21行,函数fun_three

    2、fun_three函数中的15行报错,two_num = fun_two()

    3、fun_two函数中11行报错,报错代码是:div = 10 - num,报错信息是:TypeError,不支持int类型和空类型的变量相减

    这里就是另一个错误了,输入在前,相减在后。至少说明两个问题:一、在输入时精确捕获到异常TypeError;二、捕获异常后面的代码能够正常运行。那么我虽然捕获到了异常,但程序还是异常终止了。原因在于捕获的位置不是最佳位置。尝试换一个位置来试试。

     1 #coding:utf-8
     2 
     3 def get_num():
     4     num = int(input("input you num:"))
     5     return num
     6 
     7 def fun_two():
     8     num = get_num()
     9     div = 10 -num
    10     return div
    11 
    12 def fun_three():
    13     try:
    14         two_num = fun_two()
    15         three_num = 10 / two_num 
    16         print three_num
    17     except (TypeError,ZeroDivisionError),e:
    18         print e
    19 
    20 
    21 if __name__ == '__main__':
    22     fun_three()

    将错误捕获加在最后调用的地方,并且针对两种可能出现的错误都做了捕获。那么这里理论上就能捕获两个可能出现的错误。我们看看结果如何:

    可以看到两种错误都能够捕获到,并且没有报出异常信息。以python解释器错误抛出的规则来分析:

    一、当输入为字符串“str”时,程序报错,然后解释器一层层向上寻找异常捕获的语句;

    二、在get_num()函数中没有,向上寻找调用它的函数fun_two(),任然没有;

    三、继续向上寻找调用fun_two的函数fun_three,在fun_three中寻找到捕获异常的语句except (TypeError,ZeroDivisionError),e

    四、捕获到异常之后抛出异常。

    python标准出错处理

    在编码中常用的出错处理机制是:

    try:
        可能出错的地方
    except:
        错误捕获,出错时要执行的代码
    else:
        没有错误时要执行代码
    finally:
        不管有没有错误都要执行的代码

    这种出错处理适用于不管有没有出错,都一定要执行某些操作。常见的是打开了文件,不管是否打开成功,都要关闭。

    例如:

     1 #coding:utf-8
     2 
     3 try:
     4     f = open('file.txt','w')
     5     print f.read()
     6     f.close()
     7 except IOError,e:
     8     print e
     9 else: 
    10     print f.read()
    11 finally:
    12     if f:
    13         f.close()

    以写方式打开一个文件,但是却有读操作,这样就会报错。虽然按照文件处理规范,在打开之后也添加了关闭文件的代码,报错之后的代码不会执行,所有这个错误会被except IOError捕获。但是捕获之后打开的文件并没有关闭,文件连接是消耗资源的事件,那么在finally中就要关闭文件连接。

     合适的错误捕获能够增加程序的健壮性,是在编码中一定要能够熟练使用的技巧

  • 相关阅读:
    应用环境配置记录
    【C#】Dictionary通过value获取对应的key值
    DevExpress 之 GridControl 自定义列(转)
    C#中gridView常用属性和技巧介绍(转)
    【643】cv2.imread() 函数
    【642】Python 实现膨胀、腐蚀、提取边线
    【639】keras 中 fit_generator 的 数据生成器
    【638】keras 多输出模型【实战】
    【637】一个图片两个标注的图像增强
    别自嗨了!想做新生代农民工,你还不够格。。
  • 原文地址:https://www.cnblogs.com/goldsunshine/p/9501919.html
Copyright © 2020-2023  润新知