Python 错误检查标准实践
我有一个关于 Python 错误检查的问题。假设我有一个将文件路径作为输入的函数:
def myFunction(filepath):
infile = open(filepath)
#etc etc...
一个可能的前提条件是该文件应该存在。
有几种可能的方法来检查这个前提条件,我只是想知道最好的方法是什么。
i) 使用 if 语句进行检查:
if not os.path.exists(filepath):
raise IOException('File does not exist: %s' % filepath)
这是我通常会这样做的方式,尽管如果文件不存在,Python 也会引发相同的 IOException,即使我不引发它。
ii)使用断言检查前置条件:
assert os.path.exists(filepath), 'File does not exist: %s' % filepath
使用断言似乎是检查前置/后置条件的“标准”方法,所以我很想使用它们。但是,当在执行期间使用 -o 标志时,这些断言可能会被关闭,这意味着此检查可能会被关闭,这似乎有风险。
iii)根本不处理前提条件
这是因为如果文件路径不存在,无论如何都会生成异常,并且异常消息足够详细,让用户知道该文件不存在
我只是想知道哪一个以上是我应该用于我的代码的标准做法。
I have a question regarding error checking in Python. Let's say I have a function that takes a file path as an input:
def myFunction(filepath):
infile = open(filepath)
#etc etc...
One possible precondition would be that the file should exist.
There are a few possible ways to check for this precondition, and I'm just wondering what's the best way to do it.
i) Check with an if-statement:
if not os.path.exists(filepath):
raise IOException('File does not exist: %s' % filepath)
This is the way that I would usually do it, though the same IOException would be raised by Python if the file does not exist, even if I don't raise it.
ii) Use assert to check for the precondition:
assert os.path.exists(filepath), 'File does not exist: %s' % filepath
Using asserts seems to be the "standard" way of checking for pre/postconditions, so I am tempted to use these. However, it is possible that these asserts are turned off when the -o flag is used during execution, which means that this check might potentially be turned off and that seems risky.
iii) Don't handle the precondition at all
This is because if filepath does not exist, there will be an exception generated anyway and the exception message is detailed enough for user to know that the file does not exist
I'm just wondering which of the above is the standard practice that I should use for my codes.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果您只想引发异常,请使用选项 iii:
要以特殊方式处理异常,请使用 try... except 块:
在任何情况下都不会最好先检查文件是否存在(选项
i
或ii
),因为在检查或断言发生与Python尝试打开文件之间的时间里,该文件可能会被删除或更改(例如使用符号链接),这可能会导致错误或安全漏洞。此外,从 Python 2.6 开始,打开文件的最佳实践是使用
with open(...)
语法。这保证了即使with
块内发生异常,文件也将被关闭。在 Python 2.5 中,如果您的脚本前面带有以下内容,则可以使用
with
语法If all you want to do is raise an exception, use option
iii
:To handle exceptions in a special way, use a
try...except
block:Under no circumstance is it preferable to check the existence of the file first (option
i
orii
) because in the time between when the check or assertion occurs and when python tries to open the file, it is possible that the file could be deleted, or altered (such as with a symlink), which can lead to bugs or a security hole.Also, as of Python 2.6, the best practice when opening files is to use the
with open(...)
syntax. This guarantees that the file will be closed, even if an exception occurs inside thewith
-block.In Python 2.5 you can use the
with
syntax if you preface your script with绝对不要使用断言。仅当代码错误时断言才会失败。不应使用断言检查外部条件(例如丢失文件)。
正如其他人指出的那样,可以关闭断言。
断言的正式语义是:
条件可能会或可能不会被评估(所以不要依赖于表达式的副作用)。
如果条件为真,则继续执行。
如果条件为假,会发生什么是未定义的。
有关此想法的更多信息。
Definitely don't use an assert. Asserts should only fail if the code is wrong. External conditions (such as missing files) shouldn't be checked with asserts.
As others have pointed out, asserts can be turned off.
The formal semantics of assert are:
The condition may or may not be evaluated (so don't rely on side effects of the expression).
If the condition is true, execution continues.
It is undefined what happens if the condition is false.
More on this idea.
以下内容扩展自 ~unutbu 的示例。如果文件不存在,或者发生任何其他类型的 IO 错误,文件名也会在错误消息中传递:
=> IOError:blam:没有这样的文件或目录
The following extends from ~unutbu's example. If the file doesn't exist, or on any other type of IO error, the filename is also passed along in the error message:
=> IOError: blam: No such file or directory
我认为你应该混合使用 iii) 和 i)。如果你确实知道 python 会抛出异常(即情况 iii),那么就让 python 来做吧。如果还有一些其他先决条件(例如,您的业务逻辑要求),您应该抛出自己的异常,甚至可能从
Exception
派生。恕我直言,使用断言太脆弱了,因为它们可能会被关闭。
I think you should go with a mix of iii) and i). If you know for a fact, that python will throw the exception (i.e. case iii), then let python do it. If there are some other preconditions (e.g. demanded by your business logic) you should throw own exceptions, maybe even derive from
Exception
.Using asserts is too fragile imho, because they might be turned off.