>>> from env_helper import info; info()
页面更新时间: 2024-01-20 22:03:05
运行环境:
    Linux发行版本: Debian GNU/Linux 12 (bookworm)
    操作系统内核: Linux-6.1.0-17-amd64-x86_64-with-glibc2.36
    Python版本: 3.11.2

3.7. 避免finally中可能发生的陷阱

无论 try 语句中是否有异常抛出, finally 语句总会被执行。 由于这个特性, finally 语句经 常被用来做一些清理工作,如打开一个文件,抛出异常后在 finally 语句中对文件句柄进行关闭等。 但使用 finally 时,也要特别小心一些陷阱。先来看以下例子:

3.7.1. finally 中的 break

>>>
>>> def FinallyTest():
>>>     print("i am starting----")
>>>     while True:
>>>         try :
>>>             print ("I am running")
>>>             raise IndexError ("r") #IndexError
>>>         except NameError as e:
>>>             print ('NameError happended %s',e)
>>>             break
>>>         finally:
>>>             print ("finally executed")
>>>             break #finally 句中有 break
>>> FinallyTest()
i am starting----
I am running
finally executed

上面的例子中 try 代码块抛出了 IndexError 异常,但在 except 块却没有对应的异常声明。 按常理该异常会向上层抛出,可是程序输出却没有提示任何异常发生, indexError 异常被丢失。 这是什么原因呢?当 try 块中发生异常的时候,如果在 except 语句中找不到对应的异常 处理,异常将会被临时保存起来; 当 finally 执行完毕的时候,临时保存的异常将会冉次被抛 出。 但如果 finally 语句中产生了新的异常或者执行了 return 或者 break 语句,那么临时保存 的异常将会被丢失,从而导致异常屏蔽。 这是 finally 使用时需要小心的第一个陷阱。

3.7.2. 第二个例子

再来看 另外一个例子;

>>> def ReturnTest(a):
>>>     try:
>>>         if a <=0:
>>>             raise ValueError("data can not be negative")
>>>         else:
>>>             return a
>>>     except ValueError as e:
>>>         print (e)
>>>     finally:
>>>         print ("The End")
>>>         return -1
>>> print (ReturnTest(0))
>>> print (ReturnTest(2))
data can not be negative
The End
-1
The End
-1

思考一下这里程序 RetumTest(0)RetumTest(2) 的返回值是什么?答案是:-1 , -1 。 对于第一个调用 ReturnTest(0) 在抛出 ValueError 异常后直接执行 finally 语句返回值为 -1 ,这 点比较容易理解; 那么对于笫二个调用 RetumTest(2) 为什么也返回 -1 呢? 这是因为 a>0 , 会执行 else 分支,何由于存在 finally 语句,在执行 else 语句的 return a 语句之前会先执行 finally 中的语句, 此时由于 finally 语句中有 return- 1 ,程序直接返回了,所以永远不会返回 a 对应的值 2 。 此为使用 finally 语句需要注意的第二个陷阱。 在实际应用程序开发过程屮, 并不推荐在 finally 中使用 return 语句进行返问,这种处理方式不仅会带来误解而且可能会引 起非常严重的错误。