• python的异常处理


    一、异常处理

    1、错误Error

    •  逻辑错误:算法写错了
    •  笔误:变量名写错了,语法错误
    •  函数或类的使用错误,其实这也属于逻辑错误,错误是可以避免的

    2、异常Exception

    • 本意就是意外情况,这有个前提,没有出现上面说的错误,也就是说程序写的没有问题,但是在某些情况下会出现一些意外,导致程序无法正常执行下去

    3、错误和异常

    • 在高级编程语言中,一般都是有错误和异常的概念,异常时可以捕获,并被处理的,但是错误是不能被捕获的
    •  一个健壮的程序因尽可能的避免错误,尽可能的捕获、处理各种异常

    二、产生异常

    1、产生

    • raise语句显式的抛出异常,python解释器自己检测到异常并引发它
    def foo():
        print('before')
        def bar():
            print(1/0)  # 除零异常
    
        bar()
        print('after')
    
    foo()
    
    def bar():
        print('before')
        raise Exception('my exextion')
        print('after')
    
    bar()
    
    程序会在异常抛出的地方中断执行,如果不捕获异常,就会提前结束程序


    三、异常的捕获

        try:
            待捕获异常的代码块
        except [异常类型]
            异常的处理代码块
        
    try:
        print('begin')
        c =1/0
        print('end')
    except:
        print('catch the exception')
    print('outer')
    上例执行到c=1/0时产生异常b并抛出,由于使用了try...except语句块则捕获到了这个异常
    异常生成位置之后语句将不再执行,转而执行对应的except部分的语句,最后执行try...except语句块之外的语句


    四、异常类及继承层次

    1、BaseException及子类

    •  所有内建异常类的基类是BaseException

    2、SystemExit

    •  sys.exit()函数引发的异常,异常不捕获处理,就直接交给python解释器,解释器退出
    举例1:
        import sys
        print('before')
        sys.exit(1)
    
        print('SysExit')
        print('outer')  # 是否执行
        
    举例2:
    
        #捕获这个异常
        import sys
    
        try:
            sys.exit(1)
            
        except SystemExit:
            print('SysExit')
            
        print('outer')
    
    举例3:
    
        #对应的捕获用户中断行为Ctrl + c
        try:
            import time
            while True:        
                time.sleep(0.5)
                pass
        except KeyboardInterrupt:
            print('crtl + c')
    
        print('outer')


    3、Exception及子类

    • Exception是所有内建的,非系统退出的异常的基类,自定义异常应该继承自它
    举例1:
    
        def a():
         
            try:
                0a = 5
            except:
            pass
    
    执行报错:
        File "<ipython-input-36-0e87ebfad4e3>", line 4
        0a = 5
         ^
        SyntaxError: invalid syntax 
        
        SyntaxError语法错误,python将这种错误也归到异常类下面的Exception下的子类,但是这种错误是不可捕获的
        ArithmeticError所有算术计算引发的异常,其子类除零异常等
        LookupError:使用映射的键或者序列的索引无效时引发的异常的基类:IndexError,KeyError

    4、自定义的异常,从Exception继承的类

    class MyException(Exception):
        pass
    
    
    try:
        raise MyException()
        
    except:  #捕获自定义异常
        print('cathc the exception')


    五、异常的捕获

    1、except可以捕获多个异常

    举例1:
        class MyException(Exception):
            pass
    
    
        try:
            a = 1/0
            raise MyException()  #自定义的异常
            open('a1.txt')
            
        except MyException: #捕获自定义异常
            print('cathc the MyException')
            
        except ZeroDivisionError:
            print('1/0')
        except Exception: 
            print('Exception')
        
        捕获规则:捕获是从上到下依次比较,如果匹配,则执行匹配的except语句块
                如果被一个except语句捕获,其他except语句就不会再次捕获了
                如果没有任何一个except捕获到这异常,则该异常向外抛出
        捕获原则:从小到大,从具体到宽泛


    2、as 字句

    • 被抛出的异常,应该是异常的实例,如何获取得到这个对象,使用as字句
    举例1:
        class MyException(Exception):
            def __init__(self, code, message):
                self.code = code
                self.message = message
    
        try:
            raise MyException()
            #raise MyException(200,'ok')  #raise后跟类名是无参构造实例,因此需要2个参数
            
        except MyException as e: #捕获自定义异常
            print('MyException = {}{}'.format(e.code, e.message))
            
        except Exception as e: 
            print('Exception = {}'.format(e))
    
    执行输出:Exception = __init__() missing 2 required positional arguments: 'code' and 'message'
    #执行输出:MyException = 200,ok

    3、finally子句

    • 即最后一定要执行的语句,try...finally语句块中,不管是否发生了异常,都要执行finally的部分
    举例1:
        
            f = None
            try:
                
                f = open('test.txt')
    
            except FileNotFoundError as e:
                print(e)
                print('{},{},{}'.format(e.__class__, e.errno, e.strerror))
    
            finally:
                print('清理工作')
                if f:
                    f.close()
    
        1、finally执行时机
        
        测试1:
        def foo():
            try:
                return 3
            finally:
                print('finally')
            print('===========')
        print(foo())
        执行报错:
                finally
                3
        
        进入try,执行return 3,虽然函数要返回,但是finally一定还要执行,所以打印了finally后,函数返回
        
        测试2:
        def foo():
            try:
                return 3
            finally:
                return 5
            print('===========')
        print(foo())
        
        进入try,执行return 3,虽然函数要返回,但是finally一定要执行,所以执行return 5,
        函数返回,5被压在栈顶,所以返回5,简单说,函数的返回值取决于最后一个执行的return语句
        而finally则是try...finally中最后执行的语句块
        


    六、异常的传递

    举例1:
        def foo1():
            return 1/0
    
        def foo2():
            print('foo2 start')
            foo1()
            print('foo2 stop')
    
        foo2()
        
        foo2调用了foo1,foo1产出的异常,传递到了foo2中
        异常总是向外层抛出,如果外层没有处理这个异常,就会继续向外抛出
        如果内层捕获并处理了异常,外部就不能捕获到了
        如果到了最外层还是没有被处理,就会中断异常所在的线程的执行
        
    举例2:
    #线程中测试异常
    
        import threading
        import time
    
        def foo1():
            return 1/0
    
        def foo2():
            time.sleep(3)
            print('foo2 start')
            foo1()
            print('foo2 stop')
            
        t = threading.Thread(target=foo2)
        t.start()
    
        while True:
            time.sleep(1)
            print('Everthing OK')
            if t.is_alive():
                print('alive')
            else:
                print('dead')    
        
    2、try的嵌套    
    
    举例1:
        try:
            try:
                ret = 1/0
            except KeyError as e:
                print(e)
            
            else:
                print('inner OK')
            
            finally:
                print('inner fin')
        except:
            print('outer catch')
        finally:
            print('outer fin')
                
        内部捕获不到异常,会向外层传递异常,但是如果内层有finally且其中有return,break语句,则异常就不会继续向外抛出,异常被丢弃
        
    举例2:
    
        def foo():
            try:
                ret = 1/0
            except KeyError as e:
                print(e)
            finally:
                print('inner fin')
                return   #异常被丢弃
    
        try:
            foo()
        except:
            print('outer catch')
        finally:
            print('outer fin')
            


    七、异常的捕获时机

    1、立即捕获

    需要立即返回一个明确的结果
        
        def parse_int(s):
            try:
                return int(s)
            
            except:
                return 0
    
        print(parse_int('s'))

    2、边界捕获

    • 封装产出了边界
    • 例如,写了一个模块,用户调用这个模块的时候捕获异常,模块内部不需要捕获,处理异常一旦内部处理了,外部调用者就无法感知了
    • 例如open函数,出现的异常交给调用者处理,文件存在了,就不用再创建了,看是否修改还是删除
    • 例如自己写了一个类,使用了open函数,但是出现了异常不知道如何处理,就继续向外层抛出
    •  一般来说最外层也是边界,必须处理这个异常了,否则线程退出

    3、else子句
     

        没有任何异常发生,则执行
        
        try:
            ret = 1/0
        except ArithemticError as e:
            print(e)
    
        else:
            print('OK')
        finally:
            print('fin')
            
    总结:
        try:
            <语句>   #运行别的代码
            
        except <异常类><语句>  #捕获某种类型的异常
            
        except <异常类> as <变量名>:
            <语句>  #捕获某种类型的异常并获得对象
        
        else<语句>   # 如果没有异常发生
        finally:
            <语句>   #退出try时总会执行
        


    八、try的工作原理

    • 如果try中语句执行时发生异常,搜索except子句,并执行第一个匹配该异常的except子句
    • 如果try中语句执行时发生异常,却没有匹配的except子句,异常将被递交到外层的try如果外层不处理这个异常,异常将继续向外层传递,如果都不处理该异常,则会传递到最外层,如果还没有处理,就终止异常所在线程
    • 如果在try执行时没有发生异常,将执行else子句中的语句
    • 无论try中是否发生异常,finally子句最终都会执行
  • 相关阅读:
    shell 脚本判断linux 的发行版本
    notepad++ 正则学习记录
    360 加固分析
    Android的静默安装
    Linux下调整根目录的空间大小
    linux 隐藏权限
    i针对网段开放端口 (命令行设置)
    python 删除文件/夹
    字符串截取
    echo 不换行
  • 原文地址:https://www.cnblogs.com/jiangzuofenghua/p/11450534.html
Copyright © 2020-2023  润新知