【发布时间】:2017-04-18 15:05:38
【问题描述】:
在 Python 中,有许多 built-in exceptions 可以被各种标准库函数(当然还有其他代码)抛出。某个异常可能因多种原因而引发,您可能想了解它是否因特定原因而引发。
例如,在 Windows 中,如果您在文件被另一个进程锁定时尝试移动文件,您很可能会收到 PermissionError:
PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'C:\\Path\\to\\the\\file'
就我而言,我想确定引发PermissionError 异常的原因是否是因为我尝试移动的文件被锁定,我目前通过查看我捕获的异常中的错误消息来做到这一点:
try:
# Move file
os.rename(source_path, dest_path)
except PermissionError as e:
if str(e).find('The process cannot access the file because it is being used by another process') != -1:
# File not unlocked yet; do something, e.g. wait a moment and try again
else:
# Exception thrown for some other reason; do something else
但是,检查str(e) 是否包含作为子字符串的特定错误消息并不完全安全,因为我没有看到任何specification 将分配给os.rename 引发的异常的消息当源文件被锁定时,或者应该抛出什么类型的异常,或者即使应该抛出异常。因此,这种行为可能会在未来的 Python 版本中发生变化,或者在不同的 Python 实现之间有所不同。
那么,如果我们可以假设会引发PermissionError 异常,我如何安全地确定是否由于我试图访问锁定的文件而引发了PermissionError 异常?或者,如果我们不能假设,我怎样才能安全地实现我的应用程序当前实现的相同目标?
【问题讨论】:
-
“安全”是什么意思?
-
@martineau 在这种情况下,我所说的“安全”是指如果我更改为另一个版本的 Python 或另一个 Python 解释器,它不会中断。我并不是说我目前的做法会中断,我只是不确定它不会。
-
在这种情况下,“最安全”的做法是捕获
Exception as e:并打印一条错误消息,说明无法访问该文件以及str(e)。未来无法保证。下一个最安全(也是最实用)的事情是让它相当具体,并假设未来将是兼容的,至少在可预见的未来是这样。后者通常是这种情况,因为语言创建者/维护者不喜欢破坏大量现有代码。 -
除了
str(e),你可以看看e的实际胆量。例如,vars(e)可能会显示其他内容,而不仅仅是人类可读的消息。可能在其中有用。例如,我得到的一个 sqlalchemy 异常有一个嵌入的原始异常,我可以比解析 str(e) 更容易地测试它 -
@JLPeyret
vars(e)为我返回一个空字典(e.__dict__也是一个空字典,obviously)。有趣的;我认为对象中的__dict__属性列出了对象中的所有其他属性,但显然属性可以是不可写的和those are not listed。此外,e中的属性似乎实现为properties,这是我以前没有听说过的。这可能很有用。
标签: python python-3.x exception-handling