请考虑以下代码:
def readPath(path):
content = None
if os.path.isfile(path):
f = open(path,"rb")
content = f.read()
f.close()
return content
与此相比:
def readPath(path):
content = None
try:
f = open(path,"rb")
content = f.read()
f.close()
except:
pass
return content
鉴于def被连续调用多次(数百到数千次),主要是使用有效路径(表示文件系统上的实际文件),但有时使用不存在的路径,哪个版本更有效?在打开文件之前检查条件是否比设置try块慢?
答案 0 :(得分:6)
通常,“无论使用哪个,if
或try
”,答案是 EAFP 的答案 - 要求宽恕比获得许可更容易,因此总是如此比try
更喜欢if
。但是,在这种情况下,EAFP和性能考虑都不应成为选择一个而不是另一个的理由。相反,你应该选择一个正确的。
使用isfile
因为它会使您的代码容易出现竞争条件。假设有人在您调用isfile
之后和实际打开它之前删除了文件 - 您将获得虚假异常。但是,由于代码首先检查文件的存在,权限,所有权等,然后打开它,因此出现了无数的安全漏洞 - 攻击者可能会更改链接指向的文件。 / p>
此外,open
失败的原因还有其他原因:
>>> os.path.isfile('/etc/shadow')
True
>>> open('/etc/shadow')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
PermissionError: [Errno 13] Permission denied: '/etc/shadow'
isfile
也相当于额外的系统调用,而且本身比捕获异常更昂贵;只是单独进行系统调用会使得捕获异常的开销相形见绌。正如您所说,您希望大多数文件名实际存在,isfile
所花费的时间只是额外的开销。
我在Ubuntu 16.04上使用Python 3进行了一些计时,并且os.path.isfile
对于不存在的文件进行了/etc/foo
~2μs(对于现有文件/etc/passwd
实际上更快, 1.8μs);试图打开一个不存在的文件并失败并捕获IOError
需要大约3μs - 因此使用os.path.isfile
检查文件是否存在比使用open
检查文件是否存在更快;但这不是你的代码需要做的事情:它需要读取可以读取的文件的内容,并返回其内容,为此,如果预期存在66%的文件,则open
没有检查绝对比使用isfile
首先检查要快,所以这应该是一个明智的选择。
P.S:您的代码可能会泄漏其他Pythons上的打开文件而不是CPython,并且不必要地复杂化。使用with
块,这变得更加清晰:
def read_path(path):
try:
with open(path, "rb") as f:
return f.read()
except IOError:
return None