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子句最终都会执行
原文地址:https://www.cnblogs.com/jiangzuofenghua/p/11450534.html