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

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

和这个finally的用法一样:

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

我遗漏了什么吗?


当前回答

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

其他回答

下面是一段代码来澄清两者的区别:

...

try: 
  a/b
  print('In try block')
  
except TypeError:
  print('In except block')
  
finally: 
  print('In finally block')

print('Outside')

A b = 0,1

输出:

In try block 
In finally block 
Outside

(没有错误,除了跳过块。)


A b = 1,0

输出:

In finally block

Traceback (most recent call last):
a/b
ZeroDivisionError: division by zero

(没有为ZeroDivisionError指定异常处理,只执行finally块。)


A, b = 0, '1'

输出:

In except block 
In finally block 
Outside

(异常被正确处理,程序没有中断。)


注意:如果你有一个except块来处理所有类型的错误,finally块将是多余的。

如果你早点回来,情况就不一样了:

try:
    run_code1()
except TypeError:
    run_code2()
    return None   # The finally block is run before the method returns
finally:
    other_code()

与此相比:

try:
    run_code1()
except TypeError:
    run_code2()
    return None   

other_code()  # This doesn't get run if there's an exception.

其他可能导致差异的情况:

如果在except块内抛出异常。 如果在run_code1()中抛出异常,但它不是TypeError。 其他控制流语句,如continue和break语句。

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()     

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

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


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

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