删除文件的大多数pythonic方法


453

我要删除该文件(filename如果存在)。说的合适吗

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

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


7
您是否要尝试删除文件(如果存在)(如果缺少权限则失败),或者尽力而为删除并且再也不会出现错误?
Donal Fellows

我想做@DonalFellows所说的“前者”。为此,我想斯科特的原始代码将是一个好方法?
LarsH 2013年

创建一个名为的函数unlink,并将其放在PHP命名空间中。
lama12345

1
@LarsH请参阅已接受答案的第二个代码块。如果该异常不是“没有这样的文件或目录”错误,则它将重新引发该异常。
jpmc26 2014年

Answers:


613

一种更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

17
但是,如果删除操作失败(只读文件系统或其他一些意外问题),此方法会通过吗?
斯科特·威尔逊

134
同样,文件在os.path.exists()执行时存在的事实并不意味着文件在执行时存在os.remove()
kindall

8
我的+1,但是对异常的过度使用不是Python约定:)是吗?
2012年

8
@pepr我只是在幽默地批评异常是Python中正常行为的一部分。例如,迭代器必须引发异常才能停止迭代。
马特

5
+1,因为我不能+2。除了更加Pythonic外,这一点实际上是正确的,而原始版本则不是,出于kindall建议的原因。竞态条件一样,导致安全漏洞,难以摄制臭虫等
abarnert

159

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

import contextlib

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

如果filename是一个pathlib.Path对象而不是字符串,我们可以调用其.unlink()方法而不是使用os.remove()。以我的经验,Path对象比字符串更有用。

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


7
这是截至2015年12月的最pythonic方式。Python仍在不断发展。
Mayank Jaiswal,2015年

2
我在Python 3.6上没有找到pathlib.Path对象的remove()方法
BrianHVB

1
@jeffbyrnes:我认为这违反了Python的Zen:“应该有一种-最好只有一种-显而易见的方法。” 如果您有两种方法做同样的事情,那么最终将在运行源代码时将它们混在一起,这会使读者更难理解。我怀疑他们想要与保持一致unlink(2),这是迄今为止最古老的相关接口。
凯文

1
@nivk:如果需要except子句,则应使用try/ except。它不能被有意义地缩短,因为您必须有一行来引入第一个块,该块本身,有一行来引入第二个块,然后是该块,所以try/ except已经尽可能简洁。
凯文(Kevin)

1
值得指出的是,与try / except块不同,此解决方案意味着您不必费心创建异常即可确保测试覆盖率指标相关。
thclark

50

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


4
每当我们测试存在性,然后根据该测试将其删除时,我们就会向种族条件开放。(如果文件在两者之间消失了怎么办?)
Alex L

34

本着安迪·琼斯(Andy Jones)的回答精神,如何进行真正的三元运算:

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

41
三元的滥用不当。
bgusach 2015年

19
@BrianHVB因为存在三进制,因此可以根据条件在两个值之间进行选择,而不是进行分支。
bgusach '16

1
我不喜欢将异常用于流控制。它们使代码难以理解,更重要的是可以掩盖其他可能发生的错误(例如,权限问题阻止文件删除),这些错误将导致静默失败。
Ed King

11
这不是原子的。可以在调用存在和删除之间删除该文件。尝试操作并使其失败更安全。
ConnorWGarvey

1
@ nam-g-vu仅供参考,我回滚了您的编辑,因为您基本上只是添加了原始发问人的语法作为替代。由于他们正在寻找不同于此的东西,因此我认为编辑与该特定答案没有任何关系。
蒂姆·基廷

9

知道文件是否存在并删除的另一种方法是使用模块glob。

from glob import glob
import os

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

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


8

从Python 3.8开始,请使用missing_ok=Truepathlib.Path.unlinkdocs此处

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()

1
我认为实用python3的最佳答案。
mrgnw


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

是单线的。

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


3
这很干净-我不喜欢将异常用于流控制。它们使代码难以理解,更重要的是可以掩盖其他可能发生的错误(例如,权限问题阻止文件删除),这些错误将导致静默失败。
Ed King

2
这不是很漂亮,因为它假设只有一个进程会修改文件名。这不是原子的。尝试操作并正常失败是安全正确的。令人烦恼的是Python无法标准化。如果有目录,我们将使用shutil,它将完全支持我们想要的内容。
ConnorWGarvey


1

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

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

25
这绝对不是“更多的Python语言”,实际上,这是Guido特别警告的东西,被称为布尔运算符的“滥用”。
abarnert,2012年

1
哦,我同意-问题的一部分要求采用单一方式,而这是我脑海
安迪·琼斯

4
嗯,您还可以通过仅在冒号后删除换行符来使其成为单行代码。或者,甚至更好的是,指南勉强地添加了if表达式来阻止人们“滥用布尔运算符”,并且有很大的机会证明任何东西都可能被滥用:os.remove(“ gogogo.php”)如果os.path.exists(“ gogogo.php”)否则为None。:)
abarnert 2012年

0

亲吻提供:

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

然后:

remove_if_exists("my.file")

1
如果您必须编写一个完整的函数,则可能会错过
单线的含义

@Ion Lesan OP遵循“最佳”方法来解决此问题。如果一个衬板危及可读性,它永远不是更好的方法。
巴兹(Baz)

考虑到“最佳”的固有定义,我不会在这个意义上争论,尽管它显然受到TOCTOU的影响。绝对不是KISS解决方案。
Ion Lesan

@Matt True,但是这里提供的许多解决方案都不会遇到此问题吗?
巴兹(Baz)

0

这是另一个解决方案:

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

0

带有您自己的消息的另一种解决方案。

import os

try:
    os.remove(filename)
except:
    print("Not able to delete the file %s" % filename)

-1

我曾经用过rm,它可以强制删除不存在的文件,并可以将其--preserve-root作为选项rm

--preserve-root
              do not remove `/' (default)

rm --help | grep "force"
  -f, --force           ignore nonexistent files and arguments, never prompt

我们也可以使用safe-rmsudo apt-get install safe-rm

Safe-rm是一种安全工具,旨在通过使用包装程序替换/ bin / rm来防止重要文件的意外删除,该包装程序将对给定的参数与永不删除的可配置文件和目录黑名单进行检查。

首先,我检查文件夹/文件路径是否存在。这将防止设置变量fileToRemove /folderToRemove to the string-r /`。


import os, subprocess

fileToRemove = '/home/user/fileName';
if os.path.isfile(fileToRemove):
   subprocess.run(['rm', '-f', '--preserve-root', fileToRemove]
   subprocess.run(['safe-rm', '-f', fileToRemove]

1
对于某些琐碎的事情使用shell是过大的,这种方法也无法在跨平台(例如Windows)下工作。
纳布拉

4
使用外壳程序而不是标准库(例如,os.remove)始终是执行操作的最少Pythonic / clean方法之一。例如,您必须手动处理外壳返回的错误。
纳布拉

1
我添加了答案,以rm安全使用和预防rm -r /。@JonBrave
alper

1
rm -f --preserve-root还不够好(--preserve-root无论如何可能都是默认值)。我举了-r / 一个例子,那是-r /home什么?您可能想要rm -f -- $fileToRemove,但这不是重点。
JonBrave

3
不是您使用它的方式,它带有一个变量名(环境变量),没有引号,也没有保护,没有。不是这个问题,不是。os.system('rm ...')抱歉,将粗心的人暴露在极端危险中。
JonBrave
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.