【问题标题】:Most pythonic way to delete a file which may not exist删除可能不存在的文件的大多数pythonic方法
【发布时间】:2012-06-06 02:52:06
【问题描述】:

如果文件filename 存在,我想删除它。说得对吗

if os.path.exists(filename):
    os.remove(filename)

有没有更好的方法?单线方式?

【问题讨论】:

  • 您想尝试删除存在的文件(如果缺少权限则失败)还是尽最大努力删除并且永远不会遇到错误?
  • 我想做@DonalFellows 所说的“前者”。为此,我想 Scott 的原始代码会是一个好方法吗?
  • 创建一个名为unlink的函数并将其放入命名空间PHP中。
  • @LarsH 查看已接受答案的第二个代码块。如果异常不是“没有这样的文件或目录”错误,它会重新引发异常。

标签: python


【解决方案1】:

os.path.exists 为文件夹和文件返回True。考虑使用os.path.isfile 来检查文件是否存在。

【讨论】:

  • 任何时候我们测试存在,然后根据该测试删除,我们都在向竞争条件敞开大门。 (如果文件在两者之间消失了怎么办?)
【解决方案2】:

更pythonic的方式是:

try:
    os.remove(filename)
except OSError:
    pass

虽然这需要更多的行并且看起来很丑陋,但它避免了对os.path.exists()的不必要调用,并遵循了过度使用异常的python约定。

编写一个函数来为您执行此操作可能是值得的:

import os, errno

def silentremove(filename):
    try:
        os.remove(filename)
    except OSError as e: # this would be "except OSError, e:" before Python 2.6
        if e.errno != errno.ENOENT: # errno.ENOENT = no such file or directory
            raise # re-raise exception if a different error occurred

【讨论】:

  • 但是如果删除操作失败(只读文件系统或其他一些意外问题),这会通过吗?
  • 另外,执行os.path.exists()时文件存在并不意味着执行os.remove()时文件存在。
  • 我的 +1,但过度使用异常不是 Python 约定 :) 是吗?
  • @pepr 我只是幽默地批评异常是 python 中正常行为的一部分。例如,迭代器必须引发异常以停止迭代。
  • +1 因为我不能 +2。除了更 Pythonic 之外,这个实际上是正确的,而原来的则不是,原因有点建议。诸如此类的竞争条件会导致安全漏洞、难以重现的错误等。
【解决方案3】:

这样的?利用短路评估。如果文件不存在,则整个条件不能为真,因此 python 不会打扰评估第二部分。

os.path.exists("gogogo.php") and os.remove("gogogo.php")

【讨论】:

  • 这绝对不是“更 Pythonic”——事实上,这是 Guido 特别警告的事情,并称之为布尔运算符的“滥用”。
  • 哦,我同意 - 部分问题要求采用单行方式,这是我脑海中浮现的第一件事
  • 好吧,您也可以通过删除冒号后的换行符来使其成为单行...或者,更好的是,Guide 不情愿地添加了 if 表达式以阻止人们“滥用布尔运算符” ,并且有一个很好的机会来证明任何东西都可以被滥用:os.remove("gogogo.php") if os.path.exists("gogogo.php") else None。 :)
【解决方案4】:

本着 Andy Jones 的回答精神,真正的三元运算怎么样:

os.remove(fn) if os.path.exists(fn) else None

【讨论】:

  • 丑陋地滥用三元组。
  • @BrianHVB 因为三元组可以根据条件在两个值之间进行选择,而不是进行分支。
  • 我不喜欢使用异常来进行流量控制。它们使代码难以理解,更重要的是可以掩盖一些其他发生的错误(例如阻止文件删除的权限问题),这将导致静默失败。
  • 这不是原子的。可以在调用 exists 和 remove 之间删除文件。尝试操作并让它失败会更安全。
  • @nam-g-vu 仅供参考,我回滚了您的编辑,因为您基本上只是添加了原始提问者的语法作为替代。由于他们正在寻找与此不同的东西,因此我认为编辑与此特定答案无关。
【解决方案5】:

了解文件(或文件)是否存在并删除它的另一种方法是使用模块 glob。

from glob import glob
import os

for filename in glob("*.csv"):
    os.remove(filename)

Glob 找到所有可以选择带有 *nix 通配符的模式的文件,然后循环列表。

【讨论】:

    【解决方案6】:

    我更喜欢抑制异常而不是检查文件是否存在,以避免出现TOCTTOU 错误。 Matt 的回答就是一个很好的例子,但是我们可以在 Python 3 下稍微简化它,使用contextlib.suppress()

    import contextlib
    
    with contextlib.suppress(FileNotFoundError):
        os.remove(filename)
    

    如果filenamepathlib.Path 对象而不是字符串,我们可以调用它的.unlink() 方法而不是使用os.remove()。根据我的经验,对于文件系统操作,Path 对象比字符串更有用。

    由于此答案中的所有内容都是 Python 3 独有的,因此它提供了另一个升级理由。

    【讨论】:

    • 这是 2015 年 12 月以来最 Python 的方式。不过 Python 仍在不断发展。
    • 我在 Python 3.6 上找不到 pathlib.Path 对象的 remove() 方法
    • @jeffbyrnes:我认为这违反了 Python 的禅宗:“应该有一种——最好只有一种——明显的方式来做到这一点。”如果你有两种方法做同样的事情,你最终会在运行源代码时混合使用它们,这对于读者来说更难理解。我怀疑他们希望与unlink(2) 保持一致,这是迄今为止最古老的相关界面。
    • @nivk:如果你需要一个except 子句,那么你应该使用try/except。它不能有意义地缩短,因为你必须有一行介绍第一个块,块本身,一行介绍第二个块,然后是那个块,所以try/except已经尽可能简洁了。
    • 值得指出的是,与 try/except 块不同,此解决方案意味着您不必为了确保测试覆盖率指标相关而创建异常。
    【解决方案7】:
    if os.path.exists(filename): os.remove(filename)
    

    是单行的。

    你们中的许多人可能不同意 - 可能是出于考虑使用三元组“丑陋”等原因 - 但这引出了一个问题,即我们是否应该倾听那些习惯于丑陋标准的人,当他们称非标准的东西为“丑陋”时。

    【讨论】:

    • 这很干净——我不喜欢使用异常来控制流。它们使代码难以理解,更重要的是可以掩盖一些其他发生的错误(例如阻止文件删除的权限问题),这将导致静默失败。
    • 它并不漂亮,因为它假设只有一个进程会修改文件名。它不是原子的。尝试操作并优雅地失败是安全和正确的。 Python 无法标准化,这很烦人。如果我们有一个目录,我们会使用 shutil,它会支持我们想要的。
    • 这对于您的私有工具脚本来说是可以的。这对服务器来说是不行的。原因是:竞争条件漏洞
    【解决方案8】:

    Matt's answer 是旧 Python 的正确答案,Kevin's 是新 Python 的正确答案。

    如果您不想复制silentremove 的函数,此函数在path.py 中公开为remove_p

    from path import Path
    Path(filename).remove_p()
    

    【讨论】:

      【解决方案9】:

      在 Python 3.4 或更高版本中,pythonic 的方式是:

      import os
      from contextlib import suppress
      
      with suppress(OSError):
          os.remove(filename)
      

      【讨论】:

      【解决方案10】:

      KISS 献礼:

      def remove_if_exists(filename):
        if os.path.exists(filename):
          os.remove(filename)
      

      然后:

      remove_if_exists("my.file")
      

      【讨论】:

      • 如果你必须编写一个完整的函数,它有点错过了单行代码
      • @Ion Lesan OP 正在寻找解决此问题的“最佳”方法。如果会损害可读性,那么单行线永远不会是更好的方法。
      • 鉴于“最佳”的固有广义定义,我不打算在这个意义上争论,尽管它显然受到 TOCTOU 的影响。而且绝对不是 KISS 解决方案。
      • @Matt True 但是这里提供的许多解决方案都没有遇到这个问题吗?
      【解决方案11】:

      这是另一种解决方案:

      if os.path.isfile(os.path.join(path, filename)):
          os.remove(os.path.join(path, filename))
      

      【讨论】:

        【解决方案12】:

        从 Python 3.8 开始,使用 missing_ok=Truepathlib.Path.unlink (docs here)

        from pathlib import Path
        
        my_file = Path("./dir1/dir2/file.txt")
        
        # Python 3.8+
        my_file.unlink(missing_ok=True)
        
        # Python 3.7 and earlier
        if my_file.exists():
            my_file.unlink()
        

        【讨论】:

        • 我认为实用python3的最佳答案。
        • 我在 3.8 中使用它,但作为 Path(filename).unlink(missing_ok=True)
        猜你喜欢
        • 1970-01-01
        • 2010-09-06
        • 1970-01-01
        • 1970-01-01
        • 2020-05-15
        • 2011-01-16
        • 1970-01-01
        • 1970-01-01
        • 2013-03-22
        相关资源
        最近更新 更多