687

I want to delete the file filename if it exists. Is it proper to say

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

Is there a better way? A one-line way?

5
  • 9
    Do you want to try to delete a file if it exists (and fail if you lack permissions) or to do a best-effort delete and never have an error thrown back in your face? Commented May 31, 2012 at 20:09
  • 1
    I wanted to do "the former" of what @DonalFellows said. For that, I guess Scott's original code would be a good approach? Commented Dec 11, 2013 at 15:48
  • 1
    Make a function called unlink and put it in namespace PHP. Commented Jan 31, 2014 at 18:50
  • 2
    @LarsH See the second code block of the accepted answer. It reraises the exception if the exception is anything but a "no such file or directory" error. Commented Feb 11, 2014 at 20:16
  • Could you consider accepting the answer that mentions the more recent approaches like unlink(missing_ok=True)? It's a shame on has to scroll past outdated content now. Commented Aug 14 at 12:43

14 Answers 14

836

A more pythonic way would be:

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

Although this takes even more lines and looks very ugly, it avoids the unnecessary call to os.path.exists() and follows the python convention of overusing exceptions.

It may be worthwhile to write a function to do this for you:

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
Sign up to request clarification or add additional context in comments.

24 Comments

But would this pass if the remove operation failed (read only file system or some other unexpected issue)?
Also, the fact that the file exists when os.path.exists() is executed does not mean that it exists when os.remove() is executed.
My +1, but overusing of exceptions is not a Python convention :) Or is it?
@pepr I was just humorously criticizing how exceptions are part of normal behavior in python. For example, iterators must raise exceptions in order to stop iterating.
+1 because I can't +2. Besides being more Pythonic, this one is actually correct, while the original is not, for the reason kindall suggested. Race conditions like that lead to security holes, hard-to-repro bugs, etc.
|
283

I prefer to suppress an exception rather than checking for the file's existence, to avoid a TOCTTOU bug. Matt's answer is a good example of this, but we can simplify it slightly under Python 3, using contextlib.suppress():

import contextlib

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

If filename is a pathlib.Path object instead of a string, we can call its .unlink() method instead of using os.remove(). In my experience, Path objects are more useful than strings for filesystem manipulation.

Since everything in this answer is exclusive to Python 3, it provides yet another reason to upgrade.

13 Comments

This is the most pythonic way as on December 2015. Python keeps evolving though.
I found no remove() method for pathlib.Path objects on Python 3.6
@jeffbyrnes: I'd call that a violation of the Zen of Python: "There should be one-- and preferably only one --obvious way to do it." If you had two methods which did the same thing, you would end up with a mixture of them in running source code, which would be harder for the reader to follow. I suspect they wanted consistency with unlink(2), which is by far the oldest relevant interface here.
@nivk: If you need an except clause, then you should use try/except. It cannot be meaningfully shortened, because you must have a line to introduce the first block, the block itself, a line to introduce the second block, and then that block, so try/except is already as terse as possible.
It's worth pointing out that unlike a try/except block, this solution means you don't have to mess around creating an exception in order to ensure that test coverage metrics are relevant.
|
156

As of Python 3.8, use pathlib.Path.unlink with the missing_ok=True kwarg (docs here).

Otherwise, a try/except block is the best way to do it as it is thread-safe (unlike an if/else block that checks if the file exists). In Python 3.3, the FileNotFoundError was introduced as a subclass of OSError specific to the file not existing and in Python 3.4 pathlib was added as a cleaner way to deal with the file system. So...

import pathlib  # Python >= 3.4
import os       # Python < 3.4

# Python 3.8+
pathlib.Path("./dir/file.txt").unlink(missing_ok=True)

# Python 3.4-3.7
try:
    pathlib.Path("./dir/file.txt").unlink()
except FileNotFoundError:
    pass

# Python 3.3
try:
    os.remove("./dir/file.txt")
except FileNotFoundError:
    pass

# Python 3.2 and earlier
try:
    os.remove("./dir/file.txt")
except OSError:
    pass
    

1 Comment

I use this in 3.8, but as Path(filename).unlink(missing_ok=True)
58

os.path.exists returns True for folders as well as files. Consider using os.path.isfile to check for whether the file exists instead.

1 Comment

Any time we test for existence and then remove based on that test, we are opening ourselves up to a race condition. (What if the file disappears in between?)
53

In the spirit of Andy Jones' answer, how about an authentic ternary operation:

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

7 Comments

@BrianHVB Because ternaries are there to choose between two values based on a condition, not to do branching.
I don't like to use exceptions for flow control. They make code difficult to understand and more importantly can mask some other error occurring (like a permission issue blocking a file delete) which will cause a silent fail.
This is not atomic. The file can be deleted between calls to exists and remove. It's safer to attempt the operation and allow it to fail.
@EdKing That is true if the "exception" is actually a possibility. According to PP the book, exceptions should be used for what really don't mean to happen, e.g. /etc/passwd don't exist.
@nam-g-vu Just FYI, I rolled back your edit because you basically just added the original questioner's syntax as an alternative. Since they were looking for something different than that, I don't feel that edit is germane to this particular answer.
|
22
if os.path.exists(filename): os.remove(filename)

is a one-liner.

Many of you may disagree - possibly for reasons like considering the proposed use of ternaries "ugly" - but this begs the question of whether we should listen to people used to ugly standards when they call something non-standard "ugly".

3 Comments

this is clean -- I don't like to use exceptions for flow control. They make code difficult to understand and more importantly can mask some other error occurring (like a permission issue blocking a file delete) which will cause a silent fail.
It's not pretty because it assumes there is only one process that will modify filename. It's not atomic. It's safe and correct to attempt the operation and fail gracefully. It's annoying that Python can't standardize. If we had a directory, we'd use shutil and it would support exactly what we want.
This is OK for your private tool scripts. This is NOT OK for servers. reason being: race condition vulnerability
9

Matt's answer is the right one for older Pythons and Kevin's the right answer for newer ones.

If you wish not to copy the function for silentremove, this functionality is exposed in path.py as remove_p:

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

Comments

8

Another way to know if the file (or files) exists, and to remove it, is using the module glob.

from glob import glob
import os

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

Glob finds all the files that could select the pattern with a *nix wildcard, and loops the list.

Comments

5

Since Python 3.3 you can use FileNotFoundError which is more correct than the accepted version since it doesn't ignore other possible errors.

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

1 Comment

For those just copying the snippet, it should be: except FileNotFoundError:
3

In Python 3.4 or later version, the pythonic way would be:

import os
from contextlib import suppress

with suppress(OSError):
    os.remove(filename)

1 Comment

This does not differ substantively from the answer offered here.
0

Something like this? Takes advantage of short-circuit evaluation. If the file does not exist, the whole conditional cannot be true, so python will not bother evaluation the second part.

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

3 Comments

This is definitely not "more Pythonic"—in fact, it's something Guido specifically warns about, and refers to as "abuse" of the boolean operators.
oh, I agree - part of the question asked for a one line way and this was the first thing that popped into my head
Well, you could also make it a one-liner by just removing the newline after the colon… Or, even better, Guide grudgingly added the if-expression to stop people from "abusing the boolean operators", and there's a great opportunity to prove that anything can be abused: os.remove("gogogo.php") if os.path.exists("gogogo.php") else None. :)
0

A KISS offering:

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

And then:

remove_if_exists("my.file")

5 Comments

If you have to write a whole function it kind of misses the point of one-liners
@Ion Lesan The OP is after the "best" way to solve this problem. A one liner is never a better way if it jeopardizes readability.
Given the inherently broad definition of "best", I'm not going to argue in this sense, although it's clearly affected by TOCTOU. And definitely not a KISS solution.
@Matt True but don't a number of solutions offered here suffer from this issue?
This answer is exactly the same as that one from 2014, with the same issues.
-1

This is another solution:

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

1 Comment

Downvoted because this is already covered in previous answers and is problematic because it’s not atomic. You may also want to use an intermediate variable instead of calling os.path.join twice.
-1

If glob is available.

for file in glob.glob("file/matching/pattern/*.csv"):
    os.remove(file)

1 Comment

Use a loop instead. Using list(map(…)) for side-effects makes the code harder to understand and wastes a little amount of memory since you don’t need the resulting list.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.