Varolmayan bir dosyayı silmenin en pitonik yolu


453

filenameVarsa dosyayı silmek istiyorum . Söylemek doğru mu

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

Daha iyi bir yol var mı? Tek satırlık bir yol mu?


7
Varsa (ve izinleriniz yoksa başarısız olur) bir dosyayı silmeyi mi, yoksa en iyi çabayı silme işlemini gerçekleştirmeyi mi ve asla yüzünüze bir hata atmayı denemek ister misiniz?
Donal Fellows

@ DonalFellows söylediklerini "eski" yapmak istedim. Bunun için sanırım Scott'ın orijinal kodu iyi bir yaklaşım olurdu?
LarsH

Adlı bir işlev yapın unlinkve PHP ad alanına koyun.
lama12345

1
@LarsH Kabul edilen cevabın ikinci kod bloğuna bakınız. Kural dışı durum, "böyle bir dosya veya dizin yok" hatası dışında bir şey olduğunda kural dışı durumu yeniden düzenler.
jpmc26

Yanıtlar:


614

Daha pitonik bir yol:

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

Bu daha da fazla satır alsa ve çok çirkin görünse de os.path.exists(), aşırı istisnaların python kuralına yapılan gereksiz çağrıları önler ve izler.

Bunu sizin için yapacak bir işlev yazmak faydalı olabilir:

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
Ancak bu, kaldırma işlemi başarısız olursa (salt okunur dosya sistemi veya beklenmeyen başka bir sorun) geçebilir mi?
Scott C Wilson

137
Ayrıca, dosyanın os.path.exists()yürütüldüğünde var olması , yürütüldüğünde var olduğu anlamına gelmez os.remove().
tür

8
+ 1'im, ancak istisnaların aşırı kullanımı bir Python kuralı değil :) Yoksa değil mi?
pepr

8
@pepr İstisnaların python'daki normal davranışın bir parçası olduğunu mizahi bir şekilde eleştirdim. Örneğin, yineleyiciler gerekir iterating durdurmak amacıyla özel durumlar oluşturmak.
Matt

5
+1 çünkü +2 yapamıyorum. Daha çok Pythonic olmanın yanı sıra, bu aslında doğrudur, ancak orijinal olmasa da, önerilen nedenden dolayı. Bunun gibi yarış koşulları güvenlik açıklarına, yeniden
üretilmesi

160

Bir TOCTTOU hata önlemek için, dosyanın varlığını kontrol etmek yerine bir istisna bastırmak tercih ederim . Matt'in cevabı bunun iyi bir örneğidir, ancak Python 3 altında bunu biraz basitleştirebiliriz contextlib.suppress():

import contextlib

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

Eğer filenamebir olan pathlib.Pathyerine bir dize amacı, onun çağırabilir .unlink()kullanmak yerine yöntemi os.remove(). Deneyimlerime göre, Path nesneleri dosya sistemi manipülasyonu için dizelerden daha kullanışlıdır.

Bu yanıttaki her şey Python 3'e özel olduğundan, yükseltmek için başka bir neden daha sağlar.


8
Bu, Aralık 2015'teki en pythonic yoldur. Python, gelişmeye devam ediyor.
Mayank Jaiswal

2
Python 3.6 üzerinde pathlib.Path nesneleri için remove () yöntemi bulamadım
BrianHVB

1
@jeffbyrnes: Buna Python Zen'in ihlali diyebilirim: "Bunu yapmanın bir - ve tercihen sadece bir - açık yolu olmalı." Aynı şeyi yapan iki yönteminiz varsa, kaynak kodun çalıştırılmasında bunların bir karışımı ile sonuçlanırsınız, bu da okuyucunun takip etmesi daha zor olurdu. unlink(2)Buradaki en eski ilgili arayüz olan tutarlılık istediklerinden şüpheleniyorum .
Kevin

1
@nivk: Eğer bir exceptmaddeye ihtiyacınız varsa , try/ kullanmalısınız except. Bu anlamlı Eğer birinci bloğu tanıtmak için bir çizgi olmalıdır blok kendisi bir çizgi ikinci bloğu tanıtmak çünkü kısaltılmış ve olamaz sonra blok, yani o try/ exceptolabildiğince kısa ve öz olarak zaten.
Kevin

1
Deneme / hariç tutma bloğundan farklı olarak, bu çözüm, test kapsamı metriklerinin alakalı olmasını sağlamak için bir istisna oluşturmakla uğraşmak zorunda olmadığınız anlamına gelir.
thclark

50

os.path.existsTruedosyalar ve klasörler için döner . os.path.isfileDosyanın var olup olmadığını kontrol etmek için kullanmayı düşünün .


4
Varlığı test ettiğimizde ve sonra bu teste dayanarak çıkardığımızda, kendimizi bir yarış durumuna açıyoruz. (Dosya arada kaybolursa?)
Alex L

34

Andy Jones'un cevabının ruhuna göre, otantik bir üçlü operasyona ne dersiniz:

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

41
Üçlülerin çirkin kötüye kullanımı.
bgusach

19
@BrianHVB Çünkü üçlüler bir koşula göre iki değer arasında seçim yaparlar, dallanma yapmazlar.
bgusach

1
Akış kontrolü için istisnalar kullanmak istemiyorum. Kodun anlaşılmasını zorlaştırır ve daha da önemlisi, sessiz bir başarısızlığa neden olacak başka bir hatayı (dosya silmeyi engelleyen bir izin sorunu gibi) maskeleyebilir.
Ed King

11
Bu atomik değil. Dosya mevcut çağrılar arasında silinebilir ve kaldırılabilir. İşlemi denemek ve başarısız olmasına izin vermek daha güvenlidir.
ConnorWGarvey

1
@ nam-g-vu Sadece FYI, düzenlemenizi geri aldım çünkü temel olarak orijinal sorucının sözdizimini alternatif olarak eklediniz. Bundan farklı bir şey aradıklarından, düzenlemenin bu özel cevaba alman olduğunu düşünmüyorum.
Tim Keating

11

Python 3.8'den itibaren, missing_ok=Trueve pathlib.Path.unlink( burada dokümanlar ) kullanın

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
Bence pratik python3 için en iyi cevap.
mrgnw

9

Dosyanın (veya dosyaların) var olup olmadığını bilmenin ve kaldırmanın başka bir yolu da modül globunu kullanmaktır.

from glob import glob
import os

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

Glob, * nix joker karakterli deseni seçebilecek tüm dosyaları bulur ve listeyi döngüler.



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

tek astarlıdır.

Birçoğunuz katılmıyorsunuz - muhtemelen üçlülerin "çirkin" önerilen kullanımını düşünmek gibi nedenlerle - ama bu, standart olmayan "çirkin" dediklerinde çirkin standartlar için kullanılan insanları dinleyip dinlemememiz gerektiği sorusunu akla getiriyor.


3
bu temiz - akış kontrolü için istisnalar kullanmak istemiyorum. Kodun anlaşılmasını zorlaştırır ve daha da önemlisi, sessiz bir başarısızlığa neden olacak başka bir hatayı (dosya silmeyi engelleyen bir izin sorunu gibi) maskeleyebilir.
Ed King

2
Hoş değil çünkü dosya adını değiştirecek tek bir işlem olduğunu varsayar. Atomik değil. İşlemi denemek güvenli ve doğru ve incelikle başarısız. Python'un standardize edememesi can sıkıcı bir durum. Eğer bir dizinimiz olsaydı, shutil kullanırdık ve tam istediğimizi desteklerdi.
ConnorWGarvey

2

Python 3.4 veya sonraki sürümlerinde, pythonic yolu şöyle olacaktır:

import os
from contextlib import suppress

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

3
Bu, burada sunulan cevaptan önemli ölçüde farklı değildir .
chb

1

Böyle bir şey mi? Kısa devre değerlendirmeden yararlanır. Dosya yoksa, tüm koşul doğru olamaz, bu nedenle python ikinci bölümü değerlendirmeyi rahatsız etmez.

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

25
Bu kesinlikle "daha Pythonic" değildir - aslında Guido'nun özellikle uyardığı ve boole operatörlerinin "kötüye kullanımı" olarak adlandırdığı bir şeydir.
abarnert

1
oh, katılıyorum - sorunun bir satırını istedi ve bu kafama ilk gelen şeydi
Andy Jones

4
Ayrıca, iki nokta üst üste işaretinden sonra yeni satırı kaldırarak tek satırlık yapabilirsiniz ... Ya da daha da iyisi, Guide, insanların "boolean operatörlerini kötüye kullanmasını" engellemek için if-ifadesini isteksizce ekledi ve kanıtlamak için harika bir fırsat var. istismar edilebilecek herhangi bir şey varsa: os.path.exists ("gogogo.php") halinde başka bir şey yok. :)
abarnert

0

Bir KISS şunları sunar:

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

Ve sonra:

remove_if_exists("my.file")

1
Tüm bir işlevi yazmak zorunda kalırsanız, bir tür tek noktayı kaçırır
Ion Lesan

@Ion Lesan OP bu sorunu çözmek için "en iyi" yol peşinde. Bir astar, okunabilirliği tehlikeye atarsa ​​asla daha iyi bir yol değildir.
Baz

"En iyi" nin doğası gereği geniş tanımı göz önüne alındığında, TOCTOU tarafından açıkça etkilenmesine rağmen, bu anlamda tartışmayacağım. Ve kesinlikle bir KISS çözümü değil.
Ion Lesan

@Matt Doğru ama burada sunulan bir dizi çözüm bu sorundan muzdarip değil mi?
Baz

0

Bu başka bir çözüm:

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

0

İstisnada kendi mesajınız olan başka bir çözüm.

import os

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

-1

Ben kullandım rmile varolmayan dosyaları silmek için zorlayabilir hangi --preserve-rootbir seçenek olarak rm.

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

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

Ayrıca safe-rm ( sudo apt-get install safe-rm) kullanabiliriz

Safe-rm, / bin / rm'yi bir paketleyici ile değiştirerek önemli dosyaların yanlışlıkla silinmesini önlemeyi amaçlayan bir güvenlik aracıdır ve verilen bağımsız değişkenleri hiçbir zaman kaldırılmaması gereken yapılandırılabilir bir dosya ve dizin listesine karşı kontrol eder.

Önce klasör / dosya yolunun mevcut olup olmadığını kontrol ediyorum. Bu, fileToRemove /klasörünün ayarlanmasını önleyecektirToRemove 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
Bu önemsiz bir şey için bir kabuk kullanmak aşırı derecede ağırdır ve bu yaklaşım platformlar arası da çalışmaz (Windows).
Nabla

4
Standart kitaplık yerine bir kabuk kullanmak (örneğin os.remove) her zaman bir şey yapmanın en az pythonic / clean yollarından biridir. Örneğin, kabuk tarafından döndürülen hataları elle işlemeniz gerekir.
Nabla

1
rmGüvenli bir şekilde kullanmak ve önlemek için cevabımı ekledim rm -r /. @JonBrave
alper

1
rm -f --preserve-rootyeterince iyi değil ( --preserve-rootmuhtemelen zaten varsayılan). -r / Örnek olarak verdim , -r /homeya öyleyse ya da her neyse? Muhtemelen istiyorsun rm -f -- $fileToRemove, ama mesele bu değil.
JonBrave

3
Değişken adıyla (ortam değişkeni) ve alıntı yapmadan ve koruma olmadan, kullandığınız şekilde değil, hayır. Ve bu soru için değil, hayır. Dikkatsizliğe maruz os.system('rm ...')kalmak son derece tehlikelidir, üzgünüm.
JonBrave
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.