删除可能不存在的文件的大多数pythonic方式

Sco*_*son 424 python

我想删除该文件(filename如果存在).这是否合适

if os.path.exists(filename):
    os.remove(filename)
Run Code Online (Sandbox Code Playgroud)

有没有更好的办法?单行方式?

Mat*_*att 581

一种更加pythonic的方式是:

try:
    os.remove(filename)
except OSError:
    pass
Run Code Online (Sandbox Code Playgroud)

虽然这需要更多的行并且看起来非常难看,但它避免了不必要的调用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
Run Code Online (Sandbox Code Playgroud)

  • 此外,执行`os.path.exists()`时文件存在的事实并不意味着在执行`os.remove()`时它存在. (124认同)
  • 但如果删除操作失败(只读文件系统或其他一些意外问题),这会通过吗? (16认同)
  • 我的+1,但过度使用异常不是Python惯例:)或者是它? (8认同)
  • @pepr我只是在幽默地批评异常如何成为python中正常行为的一部分.例如,迭代器**必须**引发异常才能停止迭代. (8认同)
  • +1因为我不能+2.除了更多Pythonic之外,这个实际上是正确的,而原始的不是,因为有点建议.像这样的竞争条件会导致安全漏洞,难以发现的错误等. (4认同)
  • @Matt,例外不是错误,只是特殊事件; 所以当迭代器无法继续时提升一个就是遵循这个逻辑. (3认同)
  • @ScottWilson您可以使用errno模块来解决这个问题.(我会更新我的答案). (2认同)
  • @Matt:当然,`os.remove`引发了'OSError`.[自Python 3.3起](https://docs.python.org/3/whatsnew/3.3.html#pep-3151-reworking-the-os-and-io-exception-hierarchy)这是各种操作系统的基类错误.但是你不再需要检查`errno`以获得更细粒度的信息.相反,它可能只捕获`FileNotFoundError`,但不能捕获'PermissionError`或`IsADirectoryError`.正如@Mr_and_Mrs_D已经提到的,[PEP 3151](https://www.python.org/dev/peps/pep-3151/#lack-of-fine-grained-exceptions)完全使用您的答案作为激励示例.或者我错过了什么? (2认同)
  • @stephan:哦,我明白了.`FileNotFoundError`派生自`OSError`,它实际上是`FileNotFoundError`被引发.看来`os`库的文档还没有更新.接得好!PS:我觉得PEP使用我的例子写信是有点怪异的,尽管它似乎是在我发布这个答案之前写的...... (2认同)
  • OSError 是不是有点笼统?FileNotFoundError 不会这样做吗? (2认同)

Kev*_*vin 148

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

import contextlib

with contextlib.suppress(FileNotFoundError):
    os.remove(filename)
Run Code Online (Sandbox Code Playgroud)

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

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

  • 这是2015年12月最pythonic的方式.虽然Python不断发展. (7认同)
  • 我在Python 3.6上找不到pathlib.Path对象的remove()方法 (2认同)

abo*_*ght 49

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

  • 每当我们测试存在性,然后根据该测试将其删除时,我们就会向种族条件开放。(如果文件在中间消失了怎么办?) (3认同)

wke*_*van 40

从 Python 3.8 开始,使用missing_ok=Truepathlib.Path.unlink此处为文档

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()
Run Code Online (Sandbox Code Playgroud)

  • 我认为实用 python3 的最佳答案。 (2认同)
  • 我在 3.8 中使用它,但作为 `Path(filename).unlink(missing_ok=True)` (2认同)

Tim*_*ing 36

根据Andy Jones的回答,真正的三元操作如何:

os.remove(fn) if os.path.exists(fn) else None
Run Code Online (Sandbox Code Playgroud)

  • 丑恶地滥用三元. (37认同)
  • @BrianHVB因为三元组可以根据条件在两个值之间进行选择,而不是进行分支. (18认同)
  • 这不是原子的.可以在存在和删除的调用之间删除该文件.尝试操作并使其失败更安全. (8认同)
  • @bgusach为什么丑陋? (2认同)
  • 我不喜欢使用异常来进行流程控制。它们使代码难以理解,更重要的是可以掩盖发生的一些其他错误(例如阻止文件删除的权限问题),这将导致无提示失败。 (2认同)

jot*_*cor 8

另一种知道文件(或文件)是否存在以及将其删除的方法是使用模块glob.

from glob import glob
import os

for filename in glob("*.csv"):
    os.remove(filename)
Run Code Online (Sandbox Code Playgroud)

Glob找到所有可以使用*nix通配符选择模式的文件,并循环列表.


Jas*_*mbs 7

Matt的答案是较旧的Python 的正确答案,而Kevin的答案是较新的Python 的正确答案。

如果您不想复制的功能silentremove,则此功能在path.py中显示remove_p

from path import Path
Path(filename).remove_p()
Run Code Online (Sandbox Code Playgroud)


小智 5

if os.path.exists(filename): os.remove(filename)
Run Code Online (Sandbox Code Playgroud)

是单线的。

你们中的许多人可能会不同意(可能是出于考虑将三元体系建议使用为“丑陋”的原因)的想法,但这引出了一个问题,即当人们习惯将丑陋标准称为“非丑陋”时,我们是否应该听取他们的意见。

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

Pau*_*aul 5

从 Python 3.3 开始,您可以使用FileNotFoundError比接受的版本更正确的版本,因为它不会忽略其他可能的错误。

try:
    os.remove(filename)
except FileNotFoundError:
    pass
Run Code Online (Sandbox Code Playgroud)