无论如何,最终是否确保某些代码自动获得 运行?
Does finally ensure some code gets run atomically, no matter what?
假设我要编写一个 Python 脚本来捕获 KeyboardInterrupt
异常,以便能够被用户使用 Ctrl+ 终止C平安
但是,我无法将所有关键操作(如文件写入)放入 catch
块中,因为它依赖于局部变量并确保后续的 Ctrl+C反正不破
使用带有空 (pass
) try
部分和 finally
部分内的所有代码的 try-catch 块来定义此代码段是否有效并且是一种好的做法"atomic, interrupt-safe code" 哪个不会中途被打断?
示例:
try:
with open("file.txt", "w") as f:
for i in range(1000000):
# imagine something useful that takes very long instead
data = str(data ** (data ** data))
try:
pass
finally:
# ensure that this code is not interrupted to prevent file corruption:
f.write(data)
except KeyboardInterrupt:
print("User aborted, data created so far saved in file.txt")
exit(0)
在此示例中,我不关心当前生成的数据字符串,即可以中断创建并且不会触发写入。但是一旦写入开始,它 必须 完成,这就是我想要确保的。另外,如果在 finally 子句中执行写入时发生异常(或键盘中断)会发生什么情况?
finally
中的代码也可以仍然被中断。 Python 对此不作任何保证;它所保证的是,在 try
套件完成后或 try
套件中出现异常时,执行将切换到 finally
套件。 try
只能处理在其范围内引发的异常,不能处理范围外,而 finally
在该范围外。
因此,在 pass
语句中使用 try
没有意义 。 pass 是空操作,它永远不会被打断,但是 finally
套件仍然很容易被打断。
您需要选择不同的技术。您可以写入一个单独的文件,并在成功完成后将其移动到位;例如,OS 保证文件移动是原子的。或者记录您上次成功写入的位置,如果下一次写入被中断,则将文件截断到该点。或者在您的文件中写入标记,表示记录成功,以便读取知道要忽略什么。
在你的情况下,没有问题,因为文件写入是原子的,但如果你有一些文件对象实现,那更复杂,你的 try-except
在错误的地方。您必须围绕写入放置异常处理:
try:
f.write(data)
except:
#do some action to restore file integrity
raise
例如,如果你写二进制数据,你可以这样:
filepos = f.tell()
try:
f.write(data)
except:
# remove the already written data
f.seek(filepos)
f.truncate()
raise
假设我要编写一个 Python 脚本来捕获 KeyboardInterrupt
异常,以便能够被用户使用 Ctrl+ 终止C平安
但是,我无法将所有关键操作(如文件写入)放入 catch
块中,因为它依赖于局部变量并确保后续的 Ctrl+C反正不破
使用带有空 (pass
) try
部分和 finally
部分内的所有代码的 try-catch 块来定义此代码段是否有效并且是一种好的做法"atomic, interrupt-safe code" 哪个不会中途被打断?
示例:
try:
with open("file.txt", "w") as f:
for i in range(1000000):
# imagine something useful that takes very long instead
data = str(data ** (data ** data))
try:
pass
finally:
# ensure that this code is not interrupted to prevent file corruption:
f.write(data)
except KeyboardInterrupt:
print("User aborted, data created so far saved in file.txt")
exit(0)
在此示例中,我不关心当前生成的数据字符串,即可以中断创建并且不会触发写入。但是一旦写入开始,它 必须 完成,这就是我想要确保的。另外,如果在 finally 子句中执行写入时发生异常(或键盘中断)会发生什么情况?
finally
中的代码也可以仍然被中断。 Python 对此不作任何保证;它所保证的是,在 try
套件完成后或 try
套件中出现异常时,执行将切换到 finally
套件。 try
只能处理在其范围内引发的异常,不能处理范围外,而 finally
在该范围外。
因此,在 pass
语句中使用 try
没有意义 。 pass 是空操作,它永远不会被打断,但是 finally
套件仍然很容易被打断。
您需要选择不同的技术。您可以写入一个单独的文件,并在成功完成后将其移动到位;例如,OS 保证文件移动是原子的。或者记录您上次成功写入的位置,如果下一次写入被中断,则将文件截断到该点。或者在您的文件中写入标记,表示记录成功,以便读取知道要忽略什么。
在你的情况下,没有问题,因为文件写入是原子的,但如果你有一些文件对象实现,那更复杂,你的 try-except
在错误的地方。您必须围绕写入放置异常处理:
try:
f.write(data)
except:
#do some action to restore file integrity
raise
例如,如果你写二进制数据,你可以这样:
filepos = f.tell()
try:
f.write(data)
except:
# remove the already written data
f.seek(filepos)
f.truncate()
raise