我不知道为什么我们最终需要尝试……最后陈述。在我看来,这个代码块

try:
    run_code1()
except TypeError:
    run_code2()
other_code()

和这个finally的用法一样:

try:
    run_code1()
except TypeError:
    run_code2()
finally:
    other_code()

我遗漏了什么吗?


当前回答

正如文档中所解释的,finally子句旨在定义在所有情况下都必须执行的清理操作。

如果finally存在,则指定一个' cleanup '处理程序。的尝试 子句,包括except和else子句。如果一个 异常发生在任何子句中而不被处理,则 异常被暂时保存。finally子句被执行。如果 有一个保存的异常,它在finally结束时被重新引发 条款。

一个例子:

>>> def divide(x, y):
...     try:
...         result = x / y
...     except ZeroDivisionError:
...         print("division by zero!")
...     else:
...         print("result is", result)
...     finally:
...         print("executing finally clause")
...
>>> divide(2, 1)
result is 2.0
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'

如您所见,finally子句在任何事件中都被执行。由分隔两个字符串引发的TypeError不由except子句处理,因此在finally子句执行后重新引发。

在实际应用程序中,finally子句用于释放外部资源(例如文件或网络连接),而不管资源的使用是否成功。

其他回答

为了补充上面的其他答案,无论发生什么,finally子句都会执行,而else子句只在没有引发异常时执行。

例如,写入一个没有异常的文件将输出以下内容:

file = open('test.txt', 'w')

try:
    file.write("Testing.")
    print("Writing to file.")
except IOError:
    print("Could not write to file.")
else:
    print("Write successful.")
finally:
    file.close()
    print("File closed.")

输出:

Writing to file.
Write successful.
File closed.

如果存在异常,代码将输出以下内容(注意,故意使文件保持只读会导致错误。

file = open('test.txt', 'r')

try:
    file.write("Testing.")
    print("Writing to file.")
except IOError:
    print("Could not write to file.")
else:
    print("Write successful.")
finally:
    file.close()
    print("File closed.")

输出:

Could not write to file.
File closed.

我们可以看到,无论异常如何,finally子句都会执行。希望这能有所帮助。

Finally也可以用于在运行主要工作的代码之前运行“可选”代码,而可选代码可能由于各种原因而失败。

在下面的例子中,我们不知道store_some_debug_info会抛出什么样的异常。

我们可以运行:

try:
  store_some_debug_info()
except Exception:
  pass
do_something_really_important() 

但是,大多数lint会抱怨捕捉到的异常过于模糊。此外,由于我们选择只传递错误,except块并没有真正增加值。

try:
  store_some_debug_info()
finally:
  do_something_really_important()     

上面的代码与第一个代码块具有相同的效果,但更简洁。

代码块是不等效的。如果run_code1()抛出TypeError以外的异常,或者run_code2()抛出异常,finally子句也将运行,而第一个版本中的other_code()在这些情况下不会运行。

为了让Abhijit Sahu对这个答案的评论更好看,并突出显示语法:

像这样,你可以观察到在以下情况下哪个代码块发生了什么:

try: 
    x = Hello + 20 
    x = 10 + 20 
except: 
    print 'I am in except block' 
    x = 20 + 30 
else: 
    print 'I am in else block' 
    x += 1 
finally: 
    print 'Finally x = %s' %(x) 

它们不相等。最后,不管发生什么,代码都会运行*。 它对于清理必须运行的代码非常有用。


*: 正如Mark Byers所评论的,任何导致进程立即终止的事情也会阻止最终代码的运行。 后者可以是os._exit()。或断电,但无限循环或其他东西也属于这一类。