【问题标题】:Which is faster in Python: if or try在 Python 中哪个更快:if 或 try
【发布时间】:2017-02-02 12:43:30
【问题描述】:

请考虑以下代码:

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 被连续调用很多次(数百到数千次),大部分使用有效路径(表示文件系统上的实际文件)但有时使用不存在的路径,哪个版本更有效?在打开文件之前检查条件是否比设置尝试块慢?

【问题讨论】:

标签: python


【解决方案1】:

通常,“无论使用哪个,iftry”的答案都是 EAFP - 请求宽恕比许可更容易,因此总是更喜欢 try超过if。但是,在这种情况下,EAFP 和性能考虑都不应该成为选择其中一个的理由。相反,您应该选择正确的那个。

使用isfile,因为它会使您的代码容易出现竞争条件。假设有人在您调用isfile 之后并在您实际打开它之前删除了该文件 - 您会得到一个虚假的异常。然而,由于代码首先检查文件的存在、权限、所有权等,然后打开它,因此存在无数的安全漏洞——攻击者可能会更改链接指向的文件。

此外,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:您的代码可能会在 CPython 以外的其他 Python 上泄漏打开的文件,并且不必要地复杂。使用with 块,这变得更加清晰:

def read_path(path):
    try:
        with open(path, "rb") as f:
           return f.read()
    except IOError:
        return None

【讨论】:

  • 谢谢。在我的设置中不可能出现竞态条件,但这是一个非常好的通用点。只是为了更清楚,我猜你的意思是性能考虑不应该是不选择 os.path.isfile 方法的原因。
  • @ACEGL 已更新;甚至不喜欢性能而不是正确性,允许偶尔发生崩溃等,在您的场景中使用 isfile 比使用 try-open 更可取。
猜你喜欢
  • 2011-08-11
  • 2012-06-02
  • 1970-01-01
  • 2022-10-23
  • 1970-01-01
  • 2010-09-24
  • 2011-03-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多