Python 中,finally 语句是与 try 和 except 语句配合使用的,其通常是用来做清理工作的。无论 try 中的语句是否跳入 except 中,最终都要进入 finally 语句,并执行其中的代码块。

有些时候,程序在 try 块里打开了一些物理资源(例如数据库连接、网络连接和磁盘文件等),这些物理资源都必须被显式回收。Python 的垃圾回收机制不会回收任何物理资源,只能回收内存中对象所占用的内存。

图 1 Python 异常捕获流程示意图

那么在哪里回收这些物理资源呢?在 try 块里回收,还是在 except 块中进行回收?假设程序在 try 块里进行资源回收,根据图 1 所示的异常捕获流程,如果 try 块的某条语句引发了异常,该语句后的其他语句通常不会获得执行的机会,这将导致位于该语句之后的资源回收语句得不到执行。如果在 except 块里进行资源回收,因为 except 块完全有可能得不到执行,这将导致不能及时回收这些物理资源。

为了解决这个问题,一般会在 except 的最后加个 finally 语句。不管 try 块中的代码是否出现异常,也不管哪一个 except 块被执行,甚至在 try 块或 except 块中执行了 return 语句,finally 块总会被执行。

Python 完整的异常处理语法结构如下:

try:

#业务实现代码

except SubException as e:

#异常处理块1

...

except SubException2 as e:

#异常处理块2

...

else:

#正常处理块

finally :

#资源回收块

...

各个语句块的具体执行过程,如图 1 所示:

图 1 异常处理语句块的执行流程

在异常处理语法结构中,只有 try 块是必需的,也就是说:

如果没有 try 块,则不能有后面的 except 块和 finally 块;

except 块和 finally 块都是可选的,但 except 块和 finally 块至少出现其中之一,也可以同时出现;

可以有多个 except 块,但捕获父类异常的 except 块应该位于捕获子类异常的 except 块的后面;

不能只有 try 块,既没有 except 块,也没有 finally 块;

多个 except 块必须位于 try 块之后,finally 块必须位于所有的 except 块之后。

finally 语句块和 else 语句块的区别是,else 语句块只有在没有异常发生的情况下才会执行,而 finally 语句则不管异常是否发生都会执行。不仅如此,无论是正常退出、异常退出,还是通过 break、continue、return 语句退出,finally 语句块都会执行。

例如如下程序:

import os

def test():

fis = None

try:

fis = open("a.txt")

except OSError as e:

print(e.strerror)

# return语句强制方法返回

return # ①

#os._exit(1) # ②

finally:

# 关闭磁盘文件,回收资源

if fis is not None:

try:

# 关闭资源

fis.close()

except OSError as ioe:

print(ioe.strerror)

print("执行finally块里的资源回收!")

test()

上面程序在 try 块后增加了 finally 块,用于回收在 try 块中打开的物理资源。注意在程序的 except 块中 ① 处有一条 return 语句,该语句强制方法返回。在通常情况下,一旦在方法里执行到 return 语句,程序将立即结束该方法:现在不会了,虽然 return 语句也强制方法结束,但一定会先执行 finally 块的代码。

运行上面程序,将看到如下运行结果:

No such file or directory

执行finally里的资源回收!

上面的运行结果表明在方法返回之前执行了 finally 块的代码。将 ① 处的 return 语句注释掉,取消 ② 处代码的注释,即在异常处理的 except 块中使用 os._exit(1) 语句来退出 Python 解释器。运行上面代码,将看到如下运行结果:

No such file or directory

上面的运行结果表明 finally 块没有被执行。如果在异常处理代码中使用 os.exit(1) 语句来退出 Python 解释器,则 finally 块将失去执行的机会。

除非在 try 块、except 块中调用了退出 Python 解释器的方法,否则不管在 try 块、except 块中执行怎样的代码,出现怎样的情况,异常处理的 finally 块总会被执行。调用 sys.exit() 方法退出程序不能阻止 finally 块的执行,这是因为 sys.exit() 方法本身就是通过引发 SystemExit 异常来退出程序的。

在通常情况下,不要在 finally 块中使用如 return 或 raise 等导致方法中止的语句(raise 语句将在后面介绍),一旦在 finally 块中使用了 return 或 raise 语句,将会导致 try 块、except 块中的 return、raise 语句失效。看如下程序:

def test():

try:

# 因为finally块中包含了return语句

# 所以下面的return语句失去作用

return True

finally:

return False

a = test()

print(a)

上面程序在 finally 块中定义了一条 return False 语句,这将导致 try 块中的 return true 失去作用。运行上面程序,将打印出 False 的结果。

如果 Python 程序在执行 try 块、except 块时遇到了 return 或 raise 语句,这两条语句都会导致该方法立即结束,那么系统执行这两条语句并不会结束该方法,而是去寻找该异常处理流程中的 finally 块,如果没有找到 finally 块,程序立即执行 return 或 raise 语句,方法中止;如果找到 finally 块,系统立即开始执行 finally 块,只有当 finally 块执行完成后,系统才会再次跳回来执行 try 块、except 块里的 return 或 raise 语句;如果在 finally 块里也使用了 return 或 raise 等导致方法中止的语句,finally 块己经中止了方法,系统将不会跳回去执行 try 块、except 块里的任何代码。

尽量避免在 finally 块里使用 return 或 raise 等导致方法中止的语句,否则可能出现一些很奇怪的情况。

python一个try块后接一个或多个finally块_五、Python try except finally:资源回收相关推荐

  1. 高频模拟混频器模块,功能为一个AD835乘法器+后级一个10KHz的低通滤波器,输入可以撑到100MHz,输出带宽10KHz

    高频模拟混频器模块,功能为一个AD835乘法器+后级一个10KHz的低通滤波器,输入可以撑到100MHz,输出带宽10KHz ID:62119638128398781UncleJack

  2. 高频模拟混频器模块,功能为一个AD835乘法器+后级一个10KHz的低通滤波器

    高频模拟混频器模块,功能为一个AD835乘法器+后级一个10KHz的低通滤波器,输入可以撑到100MHz,输出带宽10KHz ID:62119638128398781

  3. python一个try块后接一个或多个finally块_Effective Python(13): 合理利用try/except/else/finally结构中的每个代码块...

    一.Python的异常处理机制 Python的异常处理要考虑四种不同的时机,可用try.except.else和finally块来表述. 1. finally块 如果: 既要将异常向上传播 又要在异常 ...

  4. python程序执行完后重头开始做烧饼_Long Way To Go 之 Python 3

    集合set 集合是无序的 作用:1.去重           eg. 把list转成set可自动去重 2.关系测试     eg. 交集.并集.差集等 举个栗子:Python班有个名字列表1,Linu ...

  5. python获取数组中大于某一阈值的那些索引值_使用Python+OpenCV进行实时车道检测...

    大约十年前,当谷歌还在试验一辆原型车的时候,我想到了自己的第一辆自动驾驶汽车,当时我立刻被这个想法迷住了.不可否认的是,我必须等待一段时间,直到这些概念向社区开放,现在看来等待确实是值得的!我最近试验 ...

  6. 关于python语言数值操作符、以下选项错误的是 答案是_关于Python语言数值操作符,以下选项中描述错误的是...

    [单选题]关于Python的列表,以下选项中描述错误的是 [单选题]给定字典d,以下选项中对d.values()的描述正确的是 [单选题]下面代码的输出结果是 sum = 0 for i in ran ...

  7. 关于python语言数值操作符、以下选项错误的是 答案是_关于Python注释,以下选项中描述错误的是...

    [多选题]Python中单下划线_foo与双下划线__foo与__foo__的成员,下列说法正确的是? [单选题]关于Python语言的注释,以下选项中描述错误的是 [单选题]下面代码的输出结果是 s ...

  8. python一个try块后接一个或多个finally块_Python * with *语句是否完全等同于try-(例外)-finally块?...

    小编典典 我将不提及范围,因为它实际上并不十分相关. with EXPR as VAR: BLOCK 转换为 mgr = (EXPR) exit = type(mgr).__exit__ # Not ...

  9. python一个try块后接一个或多个finally块_Python *与*语句完全等同于一个try – (除了) – finally块?...

    我会放弃提及的范围,因为它真的不是很相关. with EXPR as VAR: BLOCK 翻译成 mgr = (EXPR) exit = type(mgr).__exit__ # Not calli ...

最新文章

  1. [HNOI2015]落忆枫音
  2. 有没有一种简单的方法可以按值删除列表元素?
  3. 理解Canvas的save()和restore()方法
  4. rocketmq发送顺序消息(四)
  5. 内存泄漏检测工具(转载)
  6. boost::coroutines模块实现斐波那契的测试程序
  7. C++动态数组简单的模拟二元堆
  8. Javascript预解析、作用域、作用域链
  9. jQuery实现滚动时动态加载页面内容
  10. 近 45 亿元拿下开源服务器 Nginx,F5 买断应用交付未来?
  11. AJAX访问JSON数据
  12. 机器人工程师入门知识框架(思维导图)
  13. Froala Editor 4.0.11 Crack
  14. Django相关文档地址
  15. 务器性能变慢 c盘temp文件夹存在大量sess开头文件的问题原因
  16. 苹果手机语音备忘录在哪_手机备忘录在哪
  17. Html+JavaScript+Css 二手车价格评估系统设计开发
  18. 通信中的DA,SA,TA,RA分别是什么意思?
  19. php动态网页验证,用动态网页技术PHP生成验证码图片的源代码
  20. 华清远见嵌入式培训_第七周回顾与反思(上)

热门文章

  1. 【矩阵论】Hermite二次型(1)
  2. 全球液晶电视稳步增长,TCL可望成为今年最大赢家
  3. 【智能优化算法-蝠鲼优化算法】基于蝠鲼优化算法求解多目标优化问题附matlab代码
  4. Java实现Execl导出
  5. 【信息学竞赛真题! ! !】信息学竞赛人必看的「NOIP2011」铺地毯 题解(C++版)
  6. strdup 和 strcpy
  7. 网站服务器响应时间1000毫秒,什么是网站响应时间?
  8. 源码方式安装的nginx注册到systemctl管理
  9. 马术路线设计相关的论文
  10. 网络实名制争议愈演愈烈是否推未知(转)