RNA*_*RNA 264 python exception-handling try-finally
我不知道为什么我们需要finally在try...except...finally声明中.在我看来,这个代码块
try:
run_code1()
except TypeError:
run_code2()
other_code()
Run Code Online (Sandbox Code Playgroud)
与使用finally以下内容相同:
try:
run_code1()
except TypeError:
run_code2()
finally:
other_code()
Run Code Online (Sandbox Code Playgroud)
我错过了什么吗?
Mar*_*ers 369
如果你早点回来,它会有所不同:
try:
run_code1()
except TypeError:
run_code2()
return None # The finally block is run before the method returns
finally:
other_code()
Run Code Online (Sandbox Code Playgroud)
与此相比:
try:
run_code1()
except TypeError:
run_code2()
return None
other_code() # This doesn't get run if there's an exception.
Run Code Online (Sandbox Code Playgroud)
其他可能导致差异的情况:
run_code1()但它不是TypeError.continue和break语句.kin*_*all 78
您可以使用它finally来确保文件或资源是否已关闭或释放,无论是否发生异常,即使您没有捕获到异常.(或者,如果您没有捕获该特定异常.)
myfile = open("test.txt", "w")
try:
myfile.write("the Answer is: ")
myfile.write(42) # raises TypeError, which will be propagated to caller
finally:
myfile.close() # will be executed before TypeError is propagated
Run Code Online (Sandbox Code Playgroud)
在这个例子中,你最好使用该with语句,但这种结构可以用于其他类型的资源.
几年后,我写了一篇关于滥用finally读者可能觉得有趣的博客文章.
Ant*_*ony 22
他们并不等同.最后,无论发生什么,代码都会运行.它对于必须运行的清理代码很有用.
Shu*_*hub 20
这是一段代码来阐明差异:
...
try:
a/b
print('In try block')
except TypeError:
print('In except block')
finally:
print('In finally block')
print('Outside')
Run Code Online (Sandbox Code Playgroud)
a, b = 0, 1
输出:
In try block
In finally block
Outside
Run Code Online (Sandbox Code Playgroud)
(没有错误,除了跳过了块。)
a, b = 1, 0
输出:
In finally block
Traceback (most recent call last):
a/b
ZeroDivisionError: division by zero
Run Code Online (Sandbox Code Playgroud)
(没有为ZeroDivisionError指定异常处理,只执行finally块。)
a, b = 0, '1'
输出:
In except block
In finally block
Outside
Run Code Online (Sandbox Code Playgroud)
(异常处理得当,程序没有中断。)
注意:如果您有except块来处理所有类型的错误,那么finally块将是多余的。
cap*_*ack 14
要添加到上面的其他答案,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.")
Run Code Online (Sandbox Code Playgroud)
OUTPUT:
Writing to file.
Write successful.
File closed.
Run Code Online (Sandbox Code Playgroud)
如果存在异常,代码将输出以下内容(请注意,将文件保持为只读会导致故意错误.
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.")
Run Code Online (Sandbox Code Playgroud)
OUTPUT:
Could not write to file.
File closed.
Run Code Online (Sandbox Code Playgroud)
我们可以看到,finally无论异常如何,该子句都会执行.希望这可以帮助.
代码块不等同.finally如果run_code1()抛出异常TypeError,或者run_code2()抛出异常,则该子句也将运行,而other_code()在这些情况下不会运行第一个版本.
在您的第一个示例中,如果run_code1()引发异常而不会发生TypeError什么?...... other_code()不会被执行.
将其与finally:版本进行比较:other_code()无论引发任何异常,都保证执行.
如文档中所述,该finally子句旨在定义在所有情况下都必须执行的清理操作。
如果
finally存在,则指定“清理”处理程序。该try子句被执行,包括anyexcept和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'
Run Code Online (Sandbox Code Playgroud)
如您所见,该finally子句在任何情况下都会执行。在TypeError通过将两个字符串凸起不被处理except子句和后因此再次加注finally条款已经被执行。
在现实世界的应用程序中,无论是否成功使用资源,finally子句对于释放外部资源(例如文件或网络连接)很有用。
多年来专业使用 delphi 教会了我如何使用finally来保护我的清理例程。Delphi 几乎强制使用finally 来清理try 块之前创建的所有资源,以免导致内存泄漏。这也是 Java、Python 和 Ruby 的工作原理。
resource = create_resource
try:
use resource
finally:
resource.cleanup
Run Code Online (Sandbox Code Playgroud)
无论您在尝试和最终之间做什么,资源都会被清理。此外,如果执行从未到达该块,它也不会被清理try。(即create_resource本身抛出异常)它使您的代码“异常安全”。
至于为什么你实际上需要一个finally块,并不是所有语言都需要。在 C++ 中,您会自动调用析构函数,当异常展开堆栈时,析构函数会强制进行清理。我认为与 try...finally 语言相比,这是朝着更清晰的代码方向迈出的一步。
{
type object1;
smart_pointer<type> object1(new type());
} // destructors are automagically called here in LIFO order so no finally required.
Run Code Online (Sandbox Code Playgroud)