在 Python 的 try 块中使用 finally 的实际例子是什么

What could be practical examples of using finally in the try block in Python

什么时候在 try..except 块中使用 finally 有意义? try..except 后面的 listing 语句不也是一样吗?

这两个有什么区别?

try:
    result = 100 / 0
except ZeroDivisionError:
    print("division by zero!")
else:
    print("result is", result)
finally:
    print("final statement")

对比

try:
    result = 100 / 0
except ZeroDivisionError:
    print("division by zero!")
else:
    print("result is", result)
print("final statement")

Isn't listing statements just after the try..except doing the same?

不,不是。您假设您已经涵盖了块可以退出的所有方式。

finally保证执行即使块退出。这包括 returncontinuebreak,不仅是例外。

对于您的具体示例,您涵盖了几乎 try 块之外的所有可能路径。但是您没有涵盖 KeyboardInterruptMemoryError。如果有人在执行过程中点击 CTRL-C,只有第一个例子会执行 print("some code at last") 行。

那是因为您的代码没有捕捉到 KeyboardInterruptMemoryError,但这些异常仍可能发生。如果 result = 100 / 0 语句引发了其中一个异常,则不会捕获异常并且 整个框架将退出 。但不是在执行 finally: 子句之前。

用另一个例子更容易演示,一个不捕获异常的例子:

mapping = {42: "The answer"}
try:
    result = mapping[42] / 17
except KeyError:
    print("Oops, no key 42 defined!")
else:
    print(result)
finally:
    del mapping

此处,finally 语句 将被执行 ,即使上面引发了 TypeError 异常:

>>> mapping = {42: "The answer"}
>>> try:
...     result = mapping[42] / 17
... except KeyError:
...     print("Oops, no key 42 defined!")
... else:
...     print(result)
... finally:
...     del mapping
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
TypeError: unsupported operand type(s) for /: 'str' and 'int'
>>> mapping  # was deleted in the `finally` block
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'mapping' is not defined

这就是 finally 通常的用途,清理资源。您甚至可以将它与 return 退出函数一起使用:

>>> def foo():
...     try:
...         return 42
...     finally:
...         print("Returning doesn't stop finally from executing!")
...     print("This is never reached")
...
>>> foo()
Returning doesn't stop finally from executing!
42

请注意 Python 也有 with statement and context managers 来帮助完成同样的工作。上下文管理器 封装 通常在 finally 中完成的清理工作,让您不必在较长的代码段末尾查找 finally 块例如,检查文件是否已关闭。

所以代替:

fileobj = open(filename)
try:
    with line in fileobj:
        # many lines of parsing code
        # .
        # etc.
        # .
finally:
    fileobj.close()

您可以使用文件对象作为上下文管理器,上面的内容被简化为:

with open(filename) as fileobj:
    with line in fileobj:
        # many lines of parsing code
        # .
        # etc.
        # .