哪个在Python中更快:if或try

时间:2016-09-24 22:03:21

标签: python

请考虑以下代码:

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块慢?

1 个答案:

答案 0 :(得分:6)

通常,“无论使用哪个,iftry”,答案是 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