• 8.6. 定义清理操作

    8.6. 定义清理操作

    try 语句有另一个可选子句,用于定义必须在所有情况下执行的清理操作。例如:

    1. >>> try:
    2. ... raise KeyboardInterrupt
    3. ... finally:
    4. ... print('Goodbye, world!')
    5. ...
    6. Goodbye, world!
    7. KeyboardInterrupt
    8. Traceback (most recent call last):
    9. File "<stdin>", line 2, in <module>

    如果存在 finally 子句,则 finally 子句将作为 try 语句结束前的最后一项任务被执行。 finally 子句不论 try 语句是否产生了异常都会被执行。 以下几点讨论了当异常发生时一些更复杂的情况:

    • 如果在执行 try 子句期间发生了异常,该异常可由一个 except 子句进行处理。 如果异常没有被 except 子句所处理,则该异常会在 finally 子句执行之后被重新引发。

    • 异常也可能在 exceptelse 子句执行期间发生。 同样地,该异常会在 finally 子句执行之后被重新引发。

    • 如果在执行 try 语句时遇到一个 break, continuereturn 语句,则 finally 子句将在执行 break, continuereturn 语句之前被执行。

    • 如果 finally 子句中包含一个 return 语句,则 finally 子句的 return 语句将在执行 try 子句的 return 语句之前取代后者被执行。

    例如

    1. >>> def bool_return():
    2. ... try:
    3. ... return True
    4. ... finally:
    5. ... return False
    6. ...
    7. >>> bool_return()
    8. False

    一个更为复杂的例子:

    1. >>> def divide(x, y):
    2. ... try:
    3. ... result = x / y
    4. ... except ZeroDivisionError:
    5. ... print("division by zero!")
    6. ... else:
    7. ... print("result is", result)
    8. ... finally:
    9. ... print("executing finally clause")
    10. ...
    11. >>> divide(2, 1)
    12. result is 2.0
    13. executing finally clause
    14. >>> divide(2, 0)
    15. division by zero!
    16. executing finally clause
    17. >>> divide("2", "1")
    18. executing finally clause
    19. Traceback (most recent call last):
    20. File "<stdin>", line 1, in <module>
    21. File "<stdin>", line 3, in divide
    22. TypeError: unsupported operand type(s) for /: 'str' and 'str'

    正如你所看到的,finally 子句在任何情况下都会被执行。 两个字符串相除所引发的 TypeError 不会由 except 子句处理,因此会在 finally 子句执行后被重新引发。

    在实际应用程序中,finally 子句对于释放外部资源(例如文件或者网络连接)非常有用,无论是否成功使用资源。