我不确定为什么我们需要finally
在try...except...finally
语句中。在我看来,这个代码块
try:
run_code1()
except TypeError:
run_code2()
other_code()
与此相同,使用finally
:
try:
run_code1()
except TypeError:
run_code2()
finally:
other_code()
我错过了什么吗?
我不确定为什么我们需要finally
在try...except...finally
语句中。在我看来,这个代码块
try:
run_code1()
except TypeError:
run_code2()
other_code()
与此相同,使用finally
:
try:
run_code1()
except TypeError:
run_code2()
finally:
other_code()
我错过了什么吗?
如果你早点回来,情况会有所不同:
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.
其他可能导致差异的情况:
run_code1()
但不是TypeError
.continue
和break
语句。You can use finally
to make sure files or resources are closed or released regardless of whether an exception occurs, even if you don't catch the exception. (Or if you don't catch that specific exception.)
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
In this example you'd be better off using the with
statement, but this kind of structure can be used for other kinds of resources.
A few years later, I wrote a blog post about an abuse of finally
that readers may find amusing.
它们不是等价的。finally
无论发生什么其他情况,代码都会运行*。它对于清理必须运行的代码很有用。
*:正如Mark Byers评论的那样,任何导致进程立即终止的事情也会阻止finally
-code 运行。后者可能是os._exit().
断电或断电,但无限循环或其他东西也属于该类别。
要添加到上面的其他答案,该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
必须执行的清理操作。
如果
finally
存在,它指定一个“清理”处理程序。该try
子句被执行,包括任何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
子句也将运行,而在第一个版本中,在这些情况下不会运行。run_code1()
TypeError
run_code2()
other_code()
In your first example, what happens if run_code1()
raises an exception that is not TypeError
? ... other_code()
will not be executed.
Compare that with the finally:
version: other_code()
is guaranteed to be executed regardless of any exception being raised.
这是一段代码来澄清差异:
...
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块将是多余的。
多年来,专业地使用 delphi 教会了我使用 finally 来保护我的清理程序。Delphi 几乎强制使用 finally 来清理在 try 块之前创建的任何资源,以免导致内存泄漏。这也是 Java、Python 和 Ruby 的工作方式。
resource = create_resource
try:
use resource
finally:
resource.cleanup
无论您在 try 和 finally 之间做什么,资源都会被清理。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.
当您想在运行主要工作的代码之前运行“可选”代码并且该可选代码可能由于各种原因而失败时,也可以使用 finally。
在下面的示例中,我们并不确切知道store_some_debug_info
可能会抛出什么样的异常。
我们可以运行:
try:
store_some_debug_info()
except Exception:
pass
do_something_really_important()
但是,大多数 linter 会抱怨捕获的异常太模糊。此外,由于我们选择仅pass
用于错误,因此该except
块并没有真正增加价值。
try:
store_some_debug_info()
finally:
do_something_really_important()
上面的代码与第一段代码的效果相同,但更简洁。
finally
用于定义“清理动作”。该finally
子句在离开try
语句之前的任何事件中都会执行,无论是否发生异常(即使您不处理它)。
我第二个@Byers 的例子。
完美的例子如下:
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)
一个 try 块只有一个强制子句:try 语句。except、else 和 finally 子句是可选的并且基于用户偏好。
finally:在 Python 离开 try 语句之前,它会在任何条件下运行 finally 块中的代码,即使它正在结束程序。例如,如果 Python 在运行 except 或 else 块中的代码时遇到错误,finally 块仍将在停止程序之前执行。
尝试在没有 finally 块的情况下先运行此代码,
1 / 0
导致除以零错误。
try:
1 / 0
print(1)
except Exception as e:
1 / 0
print(e)
然后尝试运行这段代码,
try:
1 / 0
print(1)
except Exception as e:
1 / 0
print(e)
finally:
print('finally')
对于第一种情况,您没有 finally 块,
因此当 except 块中发生错误时,程序执行将停止,并且您无法在 except 块之后执行任何操作。
但是对于第二种情况,
在程序停止之前发生错误,python首先执行finally块,然后导致程序停止。
这就是为什么你使用 finally 并做一些非常重要的事情。
运行这些 Python3 代码来观察 finally 的需求:
情况1:
count = 0
while True:
count += 1
if count > 3:
break
else:
try:
x = int(input("Enter your lock number here: "))
if x == 586:
print("Your lock has unlocked :)")
break
else:
print("Try again!!")
continue
except:
print("Invalid entry!!")
finally:
print("Your Attempts: {}".format(count))
案例2:
count = 0
while True:
count += 1
if count > 3:
break
else:
try:
x = int(input("Enter your lock number here: "))
if x == 586:
print("Your lock has unlocked :)")
break
else:
print("Try again!!")
continue
except:
print("Invalid entry!!")
print("Your Attempts: {}".format(count))
每次尝试以下输入:
** 在学习 Python 的早期阶段。
我试图在我想阅读 excel 表的地方运行代码。问题是,如果有一个没有名为的文件的文件说:SheetSum 我无法将它移动到错误位置!我写的代码是:
def read_file(data_file):
# data_file = '\rr\ex.xlsx'
sheets = {}
try:
print("Reading file: "+data_file)
sheets['df_1'] = pd.read_excel(open(data_file,'rb'), 'SheetSum')
except Exception as excpt:
print("Exception occurred", exc_info=True)
return sheets
read_file(file)
shutil.move( file, dirpath +'\\processed_files')
给出错误:
[WinError 32] 进程无法访问该文件,因为它正被另一个进程使用
我必须添加完整try except with finally
块并告诉finally
我在任何情况下都需要关闭文件,例如:
def read_file(data_file):
# data_file = '\rr\ex.xlsx'
sheets = {}
sheets_file = None
try:
print("Reading file: "+data_file)
sheets_file = open(data_file,'rb')
sheets['df_1'] = pd.read_excel(sheets_file, 'SheetSum')
except Exception as excpt:
print("Exception occurred", exc_info=True)
finally:
if sheets_file:
sheets_file.close()
return sheets
read_file(file)
shutil.move( file, dirpath +'\\processed_files')
否则,文件仍然保持打开是背景。
如果
finally
存在,它指定一个清理处理程序。该try
子句被执行,包括任何except
和else
子句。如果任一子句发生异常且未处理, 则暂时保存该异常。finally
子句被执行。finally
如果存在已保存的异常,则会在子句末尾重新引发。如果finally
子句引发另一个异常,则将保存的异常设置为新异常的上下文。
..更多在这里
只是为了让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)