finally

我们都知道无论try语句中是否抛出异常,finally中的语句一定会被执行。我们来看下面的例子:

try:
f = open("/tmp/output", "w")
f.write("hello")
#raise Exception("something wrong")
finally:
print("closing file")
f.close()

代码

不论try中写文件的过程中是否有异常,finally中关闭文件的操作一定会执行。由于finally的这个特性,finally经常被用来做一些清理工作。
我们再来看下面的例子

def func1():
try:
return
finally:
return def func2():
try:
raise ValueError()
except:
return
finally:
return print(func1())
print(func2())

例子

这个例子中 func1() 和 func2() 返回什么呢?

答案是 func1() 返回2, func2() 返回3。为什么是这样的呢?我们先来看一段Python官网上对于finally的解释:

A finally clause is always executed before leaving the try statement, whether an exception has occurred or not. When an exception has occurred in the try clause and has not been handled by an except clause (or it has occurred in a except or else clause), it is re-raised after the finally clause has been executed. The finally clause is also executed “on the way out” when any other clause of the try statement is left via a break, continue or return statement.

重点部分用粗体标出了,翻成中文就是try块中包含break、continue或者return语句的,在离开try块之前,finally中的语句也会被执行。
所以在上面的例子中,func1() 中,在try块return之前,会执行finally中的语句,try中的return被忽略了,最终返回的值是finally中return的值。func2() 中,try块中抛出异常,被except捕获,在except块return之前,执行finally中的语句,except中的return被忽略,最终返回的值是finally中return的值。
我们在上面的例子中加入print语句,可以更清楚地看到过程

def func1():
try:
print 'in func1 try: try statement, will return 1'
return
finally:
print 'in func1 finally: try statement, will return 2'
return def func2():
try:
print 'in func2 try: raise error'
raise ValueError()
except:
print 'in func2 except: caught error, will return 1!'
return
finally:
print 'in func2 finally: will return 3'
return print func1()
print func2()

加print代码

上面的代码输出

in func1 try: try statement, will return
in func1 finally: try statement, will return in func2 try: raise error
in func2 except: caught error, will return !
in func2 finally: will return

结果

我们对上面的func2做一些修改,如下

def func2():
try:
print 'in func2 try: raise error'
raise ValueError()
except IndexError:
print 'in func2 except: caught error, will return 1!'
return
finally:
print 'in func2 finally: will return 3'
return print func2()

修改代码

输出如下

in func2 try: raise error
in func2 finally: will return

结果

try中抛出的异常是ValueError类型的,而except中定位的是IndexError类型的,try中抛出的异常没有被捕获到,所以except中的语句没有被执行,但不论异常有没有被捕获,finally还是会执行,最终函数返回了finally中的返回值3。

这里还可以看到另外一个问题。try中抛出的异常没有被捕获到,按理说当finally执行完毕后,应该被再次抛出,但finally里执行了return,导致异常被丢失。
可以看到在finally中使用return会导致很多问题。实际应用中,不推荐在finally中使用return返回。

随机推荐

  1. 洛谷4643:【模板】动态dp——题解

    https://www.luogu.org/problemnew/show/P4643 很妙……让我重新又看了一遍猫锟的WC课件. 推荐一个有markdown神犇题解:https://www.cnbl ...

  2. AOJ.865 青铜莲花池 (BFS)

    AOJ.865 青铜莲花池 (BFS) 题意分析 典型的BFS 没的说 代码总览 #include <iostream> #include <cstdio> #include ...

  3. sass的mixin,extend,placeholder,function

    1. mixin 就是定义了一个函数,可以传参,并且设定默认值,css选择器可以通过@include来引用,mixin混入的代码,就是原样复制,不会合并,会造成冗余 例如: @mixin br6($b ...

  4. ContestHunter暑假欢乐赛 SRM 05

    T1 组合数,求一下乘法逆元就行了 没取模 没1LL* 爆零了 T2 让最大子段和最小就行,跑最大子段和的时候若超过S就弹出堆中最大的数,每次有负数加进来不断弹出最小的数相加重新加进堆直到为正数,因为 ...

  5. NOIP2009 codevs1173 洛谷P1073 最优贸易

    Description: 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市.任意两个城市之间最多只有一条道路直接相连.这 m 条道路中有一部分为单向通行的道路,一部分为双向通 ...

  6. mybatis主键返回的实现

    向数据库中插入数据时,大多数情况都会使用自增列或者UUID做为主键.主键的值都是插入之前无法知道的,但很多情况下我们在插入数据后需要使用刚刚插入数据的主键,比如向两张关联表A.B中插入数据(A的主键是 ...

  7. spring和Quartz的集群(二)

    一:前沿 写完了这两篇才突然想起来,忘记了最关键的东西,那就是在配置文件这里的配置,还有数据库的配置.这是郁闷啊!继续吧! 二:内容配置 我们在集成的时候需要自己配置一个quartz.properti ...

  8. bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)

    3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description ...

  9. 【C++ STL】Queue

    1.定义 class queue<>实作为一个queue(也成为FIFO,先进先出).可以使用push()将任意数量的元素置入queue中,也可以使用pop()将元素以其插入顺序从容器中移 ...

  10. 安装显卡后蓝屏0x00000116解决办法

    1. 亲自遇到蓝屏的问题. 2. 进入安全模式后重装系统,成功. 3. 安装驱动,软件没毛病.安装显卡驱动后,蓝屏. 4. 查看蓝屏错误代码0x00000116, 百度后查看到是显卡驱动的问题. 5. ...