Python-try except else finally有return时执行顺序探究——finally语句无论如何也是会执行的

Python-try except else finally有return时执行顺序探究

下面这段代码:

1
2
3
4
5
6
7
8
9
def calculate(division):
        try:
                return 100/division
        except ZeroDivisionError as e:
                print("fuck")
                raise ValueError("Invali")
        finally :
                return 0
print(calculate(0))  

打印fuck 0

不会抛出invaild的valueerror异常。

 

学习python或者其他有异常控制的编程语 言, 大家很有可能说try except finally(try catch finally)的执行很简单,无非就是有异常的话执行except, finally无论是否有异常都会执行, 大致上原则是这样, 但是如果涉及到更加详细的复杂的路径,加上return 语句,就没有那么简单了。

1. 没有return 语句的情况

复制代码
复制代码
print 'this is a test of code path in try...except...else...finally'
print '************************************************************'
 
def exceptTest():
    try:
        print 'doing some work, and maybe exception will be raised'
        raise IndexError('index error')
        #print 'after exception raise'
        #return 0
         
    except KeyError, e:
        print 'in KeyError except'
        print e
        #return 1
    except IndexError, e:
        print 'in IndexError except'
        print e
        #return 2
    except ZeroDivisionError, e:
        print 'in ZeroDivisionError'
        print e
        #return 3
    else:
        print 'no exception'
        #return 4
    finally:
        print 'in finally'
        #return 5
 
resultCode = exceptTest()
print resultCode
复制代码
复制代码
上面的代码是一直要使用的代码,只不过暂时不用的代码被comment了。

有异常发生,并且捕获异常,最后在finally进行处理,上面代码的输出:

复制代码
复制代码
this is a test of code path in try...except...else...finally
************************************************************
doing some work, and maybe exception will be raised
in IndexError except
index error
in finally
None
复制代码
复制代码

然后我们逐渐给上面代码各个情况添加return 语句, 查看添加return 语句后的代码执行效果。

2. 添加return 语句的情况

复制代码
复制代码
print 'this is a test of code path in try...except...else...finally'
print '************************************************************'
 
def exceptTest():
    try:
        print 'doing some work, and maybe exception will be raised'
        raise IndexError('index error')
        print 'after exception raise'
        return 0
         
    except KeyError, e:
        print 'in KeyError except'
        print e
        return 1
    except IndexError, e:
        print 'in IndexError except'
        print e
        return 2
    except ZeroDivisionError, e:
        print 'in ZeroDivisionError'
        print e
        return 3
    else:
        print 'no exception'
        return 4
    finally:
        print 'in finally'
        return 5
 
resultCode = exceptTest()
print resultCode
复制代码
复制代码

这个时候所有的分支都存在return 语句,并且会引发异常, 看一下输出:

复制代码
复制代码
this is a test of code path in try...except...else...finally
************************************************************
doing some work, and maybe exception will be raised
in IndexError except
index error
in finally
5
复制代码
复制代码

异常发生后,raise语句以后的不再执行,然后到了捕获异常语句, 但是捕获异常模块有个return , 是不是这个时候就不再继续执行直接返回呢?但是这是跟 finally语句必然执行是相冲突的, 可以在结果中看到finally实际上执行了,并且返回值是5,在 finally de 的返回值。

然后,我们在看看把finally 的返回值注释掉,看看返回值是多少?

代码如下:

复制代码
复制代码
print 'this is a test of code path in try...except...else...finally'
print '************************************************************'
 
def exceptTest():
    try:
        print 'doing some work, and maybe exception will be raised'
        raise IndexError('index error')
        print 'after exception raise'
        return 0
         
    except KeyError, e:
        print 'in KeyError except'
        print e
        return 1
    except IndexError, e:
        print 'in IndexError except'
        print e
        return 2
    except ZeroDivisionError, e:
        print 'in ZeroDivisionError'
        print e
        return 3
    else:
        print 'no exception'
        return 4
    finally:
        print 'in finally'
        #return 5
 
resultCode = exceptTest()
print resultCode
复制代码
复制代码

这个时候的程序输出:

复制代码
复制代码
this is a test of code path in try...except...else...finally
************************************************************
doing some work, and maybe exception will be raised
in IndexError except
index error
in finally
2
复制代码
复制代码

返回值变为2, 这个时候有点疑惑了, 先不用解释问题,我们继续看其他的情况。

3. 没有异常发生且try语句块没有return

代码如下:

复制代码
复制代码
print 'this is a test of code path in try...except...else...finally'
print '************************************************************'
 
def exceptTest():
    try:
        print 'doing some work, and maybe exception will be raised'
        #raise IndexError('index error')
        print 'after exception raise'
        #return 0
         
    except KeyError, e:
        print 'in KeyError except'
        print e
        return 1
    except IndexError, e:
        print 'in IndexError except'
        print e
        return 2
    except ZeroDivisionError, e:
        print 'in ZeroDivisionError'
        print e
        return 3
    else:
        print 'no exception'
        return 4
    finally:
        print 'in finally'
        return 5
 
resultCode = exceptTest()
print resultCode
复制代码
复制代码

这个时候的代码输出:

复制代码
复制代码
this is a test of code path in try...except...else...finally
************************************************************
doing some work, and maybe exception will be raised
after exception raise
no exception
in finally
5
复制代码
复制代码

这里验证了如果没有异常那么else语句是执行的,并且finally语句执行,然后返回finally语句的return 5

但是,当try语句块里存在return语句是什么情况呢?

4. 没有异常发生且try语句块 存在return语句

复制代码
复制代码
print 'this is a test of code path in try...except...else...finally'
print '************************************************************'
 
def exceptTest():
    try:
        print 'doing some work, and maybe exception will be raised'
        #raise IndexError('index error')
        print 'after exception raise'
        return 0
         
    except KeyError, e:
        print 'in KeyError except'
        print e
        return 1
    except IndexError, e:
        print 'in IndexError except'
        print e
        return 2
    except ZeroDivisionError, e:
        print 'in ZeroDivisionError'
        print e
        return 3
    else:
        print 'no exception'
        return 4
    finally:
        print 'in finally'
        return 5
 
resultCode = exceptTest()
print resultCode
复制代码
复制代码

执行结果:

复制代码
复制代码
this is a test of code path in try...except...else...finally
************************************************************
doing some work, and maybe exception will be raised
after exception raise
in finally
5
复制代码
复制代码

这里else没有执行,和我们对于书本知识有冲突了, finally语句执行并返回5.

分析: 这里因为没有发生异常, 所以会执行到try块中的return 语句,但是finally又必须执行,所以执行try中return 之前去执行了finally语句,并且可以认为,finally语句修改了最后返回的值,将try中的返回值修改为5并最终返回,所以else语句并没有 得到执行。

5. 有异常发生并且finally 没有return 语句

复制代码
复制代码
print 'this is a test of code path in try...except...else...finally'
print '************************************************************'
 
def exceptTest():
    try:
        print 'doing some work, and maybe exception will be raised'
        raise IndexError('index error')
        print 'after exception raise'
        return 0
         
    except KeyError, e:
        print 'in KeyError except'
        print e
        return 1
    except IndexError, e:
        print 'in IndexError except'
        print e
        return 2
    except ZeroDivisionError, e:
        print 'in ZeroDivisionError'
        print e
        return 3
    else:
        print 'no exception'
        return 4
    finally:
        print 'in finally'
        #return 5
 
resultCode = exceptTest()
print resultCode
复制代码
复制代码

执行结果:

复制代码
复制代码
this is a test of code path in try...except...else...finally
************************************************************
doing some work, and maybe exception will be raised
in IndexError except
index error
in finally
2
复制代码
复制代码

因为有异常发生,所以try中的return语句肯定是执行不到的,然后在捕获到的except中进行执行,并且except中存在return 语句,那么是不是就直接返回? 因为finally 语句是必须要执行的,所以这里的return语句需要先暂且放下,进入finally进行执行,然后finnaly执行完以后再返回到 except中进行执行。

看到这里,我们貌似找到了一些规律

1. 如果没有异常发生, try中有return 语句, 这个时候else块中的代码是没有办法执行到的, 但是finally语句中如果有return 语句会修改最终的返回值, 我个人理解的是try中return 语句先将要返回的值放在某个 CPU寄存器,然后运行finally语句的时候修改了这个寄存器的值,最后在返回到try中的return语句返回修改后的值。

2. 如果没有异常发生, try中没有return语句,那么else块的代码是执行的,但是如果else中有return, 那么也要先执行finally的代码, 返回值的修改与上面一条一致。

3. 如果有异常发生,try中的return语句肯定是执行不到, 在捕获异常的 except语句中,如果存在return语句,那么也要先执行finally的代码,finally里面的代码会修改最终的返回值,然后在从 except 块的retrun 语句返回最终修改的返回值, 和第一条一致。

转自:http://www.2cto.com/kf/201405/304975.html

posted @   bonelee  阅读(691)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
历史上的今天:
2018-03-25 leetcode 453. Minimum Moves to Equal Array Elements
2018-03-25 leetcode 492. Construct the Rectangle
2018-03-25 leetcode 598. Range Addition II
2018-03-25 leetcode 349. Intersection of Two Arrays
2018-03-25 leetcode 171. Excel Sheet Column Number
2017-03-25 es的forcemerge——按照天分割
2017-03-25 facebook Presto SQL分析引擎——本质上和spark无异,分解stage,task,MR计算
点击右上角即可分享
微信分享提示