• python中 try、except、finally执行顺序


    我们虽然经常用到try...except 作为异常补货,但是其实很少去研究try源码和机制,也许点进去看过,也是看不出个所以然来

    class Exception(BaseException):
        """ Common base class for all non-exit exceptions. """
        def __init__(self, *args, **kwargs): # real signature unknown
            pass

    继承了BaseException

    class BaseException(object):
        """ Common base class for all exceptions """
        def with_traceback(self, tb): # real signature unknown; restored from __doc__
            """
            Exception.with_traceback(tb) --
                set self.__traceback__ to tb and return self.
            """
            pass
    
        def __delattr__(self, *args, **kwargs): # real signature unknown
            """ Implement delattr(self, name). """
            pass
    
        def __getattribute__(self, *args, **kwargs): # real signature unknown
            """ Return getattr(self, name). """
            pass
    
        def __init__(self, *args, **kwargs): # real signature unknown
            pass
    ..................

     是不是仍然一脸懵逼,同感,哈哈,那还是直接上代码,事实大于雄辩

    代码举例转自https://blog.csdn.net/u010159842/article/details/54924940 我觉得这个作者写的很清楚

    一:在 try 中 raise一个异常,就立刻转入 except 中执行,在except 中遇到 return 时,就强制转到 finally 中执行, 在 finally 中遇到 return 时就返回,最终函数返回值是finally 返回的

    ef test1():
       try:
          print('to do stuff')
          raise Exception('hehe')
          print('to return in try')
          return 'try'
     except Exception:
          print('process except')return 'except'
     finally:
          print('to return in finally')
          return 'finally'
    
    test1Return = test1()
    print('test1Return : ' + test1Return)
    #输出:
    
    #to do stuff
    #process except
    #to return in finally
    #test1Return : finally

    二:这里在 try 中没有抛出异常,因此不会转到 except 中,但是在try 中遇到return时,也会立即强制转到finally中执行,并在finally中返回

    def test2():
       try:
          print('to do stuff')
          print('to return in try')
          return 'try'
     except Exception:
          print('process except')
          print('to return in except')
          return 'except'
     finally:
          print('to return in finally')
          return 'finally'
    
    test2Return = test2()
    print('test1Return : ' + test2Return)
    #输出:
    #to do stuff
    #to return in try
    #to return in finally
    #test2Return : finally

    test1和test2得到的结论:

    无论是在try还是在except中,遇到return时,只要设定了finally语句,就会中断当前的return语句,跳转到finally中执行,如果finally中遇到return语句,就直接返回,不再跳转回try/excpet中被中断的return语句

    def test3():
       i = 0
     try:
          i += 1
     print('i in try : %s'%i)
          raise Exception('hehe')
     except Exception:
          i += 1
     print('i in except : %s'%i)
          return i
          finally:
          i += 1
     print ('i in finally : %s'%i )
    
    print('test3Return : %s'% test3())
    #输出:
    
    #i in try : 1
    #i in except : 2
    #i in finally : 3
    #test3Return : 2
    def test4():
       i = 0
     try:
          i += 1
     return i
       finally:
          i += 1
     print ('i in finally : %s'%i )
    print('test4Return : %s' % test4())
    #输出
    #i in finally : 2
    #test4Return : 1

    test3和test4得到的结论:

    在except和try中遇到return时,会锁定return的值,然后跳转到finally中,如果finally中没有return语句,则finally执行完毕之后仍返回原return点,将之前锁定的值返回(即finally中的动作不影响返回值),如果finally中有return语句,则执行finally中的return语句。

    四:test5得到的结论:在一个循环中,最终要跳出循环之前,会先转到finally执行,执行完毕之后才开始下一轮循环

    def test5():
       for i in range(5):
          try:
             print('do stuff %s'%i)
             raise Exception(i)
          except Exception:
             print('exception %s'%i)
             continue
     finally:
             print('do finally %s'%i)
    test5()
    输出
    
    do stuff 0
    exception 0
    do finally 0
    do stuff 1
    exception 1
    do finally 1
    do stuff 2
    exception 2
    do finally 2
    do stuff 3
    exception 3
    do finally 3
    do stuff 4
    exception 4
    do finally 4
    View Code

    注:

    python的错误也是class,所有的错误类型都继承自BaseException,各个类型的错误之间可能会存在继承关系,比如UnicodeError是ValueError的子类,
    如果catch语句中同时出现了这两个错误,且UnicodeError在ValueError的后面处理的,那么永远都捕获不到UnicodeError。

    python中内置的常用错误类型继承关系:

    使用try…excetp捕获错误一个好处是,可以跨层调用,比如main()调用foo(),foo()调用bar(),而错误是在bar中出现的,最后我们只需要在main()中捕获就行。

    五:举个工作中的例子

    # 首先下面的代码是一段有问题的代码哦,是对try机制了解不清晰
    import time
    def pushMsg(ss):
        try:
            res=10/ss         # 设置报错点
            if res:
                return res
        except Exception as e:
            return False
    # 该函数需求是调用pushMsg()函数,默认三次不成功返回,就不再调用
    def exceptTest(ss):
        cnt = 1
        while cnt <= 3:
            try:
                res = pushMsg(ss)
                print("res:",res)
                if res:
                    break    # 如果正常返回了,退出循环
            except Exception as e:
                print(e)
                continue   # 本意收集
            finally:
                cnt += 1
                time.sleep(1)
                print("cnt",cnt)
        if cnt > 3:
            print("3 times push failed!")
        return True
    
    # 分两种情况(主要考量except和finall,在两层套用情况下执行顺序,也就是内层函数也用了try ,并且return False)
    # 第一种:程序正常走下来,不设置错误 ss传值非零
    ss=1
    exceptTest(ss)
    # 打印执行顺序:只有  res: 10.0,因为内外两层try ,都没有捕获到错误,except和finally 里面都没有执行打印,并且判断res有值就直接break退出循环了
    
    
    # 第二种情况,置报错 ss传值为零
    ss=0
    exceptTest(ss)
    
    # 打印执行顺序:下面的顺序,先打印了finally里面的内容,再打印了返回值res,但是!为什么except里面的东西没有打印呢!
    """
    cnt 2
    res: False
    cnt 2
    res: False
    cnt 3
    res: False
    cnt 4
    3 times push failed!
    """
    # 总结上面两种情况,无论是有无异常,except里面的东西都没有执行,那外层的try根本没有用呀,这是为什么呢!
    # 经过研究,发现内层函数pushMsg(ss),也用了try ,但是他直接return True或者False ,并没有把内层捕获到的错误传到外层,所以外层的try也就捕获不到异常了,y
    # 外层函数就会默认没有错误,直接执行finally里面的内容
    那么代码就可以这么改
    def pushMsg(ss):
        try:
            res=10/ss         # 设置报错点
            if res:
                return res
        except Exception as e:
            import traceback
            traceback.print_exc()
            return False
    
    def exceptTest(ss):
    
        cnt = 1
        while cnt <= 3:
            res = pushMsg(ss)
            print("res:", res)
            if res:
                break
            else:
                cnt += 1
                time.sleep(1)
        if cnt > 3:
            print("3 times push failed!")
        return True
  • 相关阅读:
    线程带参数操作
    静态页面不识别include
    当网站遭遇DDOS攻击的解决方案及展望
    带进度条上传控件
    用js实现了表格数据管理的以下几个功能:
    怎么面试一个人
    map的使用
    在Axapta中实现trim函数
    Axapta财务过账分析(一)
    在Axapta中实现split函数
  • 原文地址:https://www.cnblogs.com/zzy-9318/p/10120538.html
Copyright © 2020-2023  润新知