Deseja tentar excluir um arquivo, se ele existir (e falhar se você não tiver permissões), ou fazer uma exclusão com o máximo de esforço e nunca receber um erro na sua cara?
Donal Fellows
Eu queria fazer "o primeiro" do que o @DonalFellows disse. Por isso, acho que o código original de Scott seria uma boa abordagem?
Larsh
Crie uma função chamada unlinke coloque-a no espaço para nome PHP.
Lama12345
1
@LarsH Veja o segundo bloco de código da resposta aceita. Ele gera novamente a exceção se a exceção for qualquer coisa, exceto um erro "sem esse arquivo ou diretório".
Jpmc26
Respostas:
613
Uma maneira mais pitônica seria:
try:
os.remove(filename)exceptOSError:pass
Embora isso exija ainda mais linhas e pareça muito feio, evita a chamada desnecessária os.path.exists()e segue a convenção python de excessivas exceções.
Pode valer a pena escrever uma função para fazer isso por você:
import os, errnodef silentremove(filename):try:
os.remove(filename)exceptOSErroras e:# this would be "except OSError, e:" before Python 2.6if e.errno != errno.ENOENT:# errno.ENOENT = no such file or directoryraise# re-raise exception if a different error occurred
Mas isso passaria se a operação de remoção falhasse (sistema de arquivos somente leitura ou outro problema inesperado)?
Scott C Wilson
135
Além disso, o fato de o arquivo existir quando os.path.exists()é executado não significa que ele existe quando os.remove()é executado.
kindall 31/05
8
Meu +1, mas o uso excessivo de exceções não é uma convenção do Python :) Ou é?
pepr 31/05
8
@pepr Eu estava criticando humoristicamente como as exceções fazem parte do comportamento normal em python. Por exemplo, os iteradores devem gerar exceções para interromper a iteração.
Matt
5
+1 porque não posso +2. Além de ser mais pitonico, este é realmente correto, enquanto o original não é, pelo motivo sugerido por todos. Condições de corrida como que levam a falhas de segurança, bugs difíceis de repro, etc.
abarnert
159
Prefiro suprimir uma exceção em vez de verificar a existência do arquivo, para evitar um bug do TOCTTOU . A resposta de Matt é um bom exemplo disso, mas podemos simplificá-lo um pouco no Python 3, usando contextlib.suppress():
Se filenameé um pathlib.Pathobjeto em vez de uma string, podemos chamar seu .unlink()método em vez de usar os.remove(). Na minha experiência, os objetos Path são mais úteis que as strings para manipulação do sistema de arquivos.
Como tudo nesta resposta é exclusivo do Python 3, ele fornece mais um motivo para a atualização.
Essa é a maneira mais pitônica de dezembro de 2015. Embora o Python continue evoluindo.
Mayank Jaiswal
2
I encontrado nenhum método de remoção () para pathlib.Path objetos em Python 3,6
BrianHVB
1
@jeffbyrnes: Eu chamaria isso de violação do Zen de Python: "Deveria haver uma - e de preferência apenas uma - maneira óbvia de fazer isso". Se você tivesse dois métodos que fizeram a mesma coisa, você acabaria com uma mistura deles na execução do código-fonte, o que seria mais difícil para o leitor seguir. Eu suspeito que eles queriam consistência com unlink(2), que é de longe a interface relevante mais antiga aqui.
Kevin
1
@nivk: Se você precisar de uma exceptcláusula, deverá usar try/ except. Ele não pode ser significativamente reduzido, porque você deve ter uma linha para introduzir o primeiro bloco, o bloco em si, uma linha para introduzir o segundo bloco, e depois que o bloco, de modo try/ exceptjá é tão concisa quanto possível.
Kevin Kevin
1
Vale ressaltar que, diferentemente de um bloco try / except, essa solução significa que você não precisa mexer na criação de uma exceção para garantir que as métricas de cobertura de teste sejam relevantes.
Thdark #
50
os.path.existsretorna Truepara pastas e arquivos. Considere usar os.path.isfilepara verificar se o arquivo existe.
Sempre que testamos a existência e removemos com base nesse teste, estamos nos abrindo para uma condição de corrida. (E se o arquivo desaparece no meio?)
Alex L
34
No espírito da resposta de Andy Jones, que tal uma autêntica operação ternária:
@BrianHVB Como existem ternários para escolher entre dois valores com base em uma condição, não para ramificação.
bgusach
1
Não gosto de usar exceções para controle de fluxo. Eles dificultam o entendimento do código e, mais importante, podem mascarar outros erros (como um problema de permissão que bloqueia a exclusão de um arquivo) que causam uma falha silenciosa.
Ed King
11
Isso não é atômico. O arquivo pode ser excluído entre as chamadas para existir e remover. É mais seguro tentar a operação e permitir que ela falhe.
ConnorWGarvey
1
@ nam-g-vu Recentemente, revirei sua edição porque você basicamente adicionou a sintaxe do questionador original como alternativa. Como eles procuravam algo diferente, não acho que a edição seja pertinente a essa resposta específica.
Tim Keating
9
Outra maneira de saber se o arquivo (ou arquivos) existe e removê-lo é usando o módulo glob.
from glob import glob
import os
for filename in glob("*.csv"):
os.remove(filename)
O Glob encontra todos os arquivos que poderiam selecionar o padrão com um curinga * nix e faz um loop na lista.
Muitos de vocês podem discordar - possivelmente por razões como considerar o uso proposto de ternários "feio" - mas isso levanta a questão de saber se devemos ouvir as pessoas acostumadas a padrões feios quando chamam algo não-padrão de "feio".
isso é limpo - não gosto de usar exceções para controle de fluxo. Eles dificultam o entendimento do código e, mais importante, podem mascarar outros erros (como um problema de permissão que bloqueia a exclusão de um arquivo) que causam uma falha silenciosa.
Ed King
2
Não é bonito porque assume que há apenas um processo que modificará o nome do arquivo. Não é atômico. É seguro e correto tentar a operação e falhar normalmente. É irritante que o Python não possa padronizar. Se tivéssemos um diretório, usaríamos shutil e suportaria exatamente o que queremos.
ConnorWGarvey
2
No Python 3.4 ou versão posterior, a maneira pitônica seria:
import os
from contextlib import suppress
with suppress(OSError):
os.remove(filename)
Algo assim? Aproveita a avaliação de curto-circuito. Se o arquivo não existir, toda a condicional não poderá ser verdadeira; portanto, o python não incomodará a avaliação da segunda parte.
Definitivamente, isso não é "mais pitonico" - na verdade, é algo sobre o qual Guido especificamente alerta e se refere como "abuso" dos operadores booleanos.
abarnert
1
oh, eu concordo - parte da pergunta pedia uma via única e essa foi a primeira coisa que me veio à cabeça
Andy Jones
4
Bem, você também pode torná-lo uma linha única removendo a nova linha após os dois pontos ... Ou, melhor ainda, o Guide acrescentou de má vontade a expressão if para impedir as pessoas de "abusarem dos operadores booleanos", e há uma grande oportunidade para provar que qualquer coisa pode ser abusada: os.remove ("gogogo.php") se os.path.exists ("gogogo.php") else Nenhum. :)
Se você tem que escrever uma função todo, tipo de perde o ponto de one-liners
Ion Lesan
@Ion Lesan O OP está atrás da "melhor" maneira de resolver esse problema. Um liner nunca é a melhor maneira se comprometer a legibilidade.
Baz
Dada a definição inerentemente ampla de "melhor", não vou discutir neste sentido, embora seja claramente afetado pelo TOCTOU. E definitivamente não é uma solução do KISS.
Ion Lesan
@ Matt True, mas várias soluções oferecidas aqui não sofrem com esse problema?
Baz
0
Esta é outra solução:
if os.path.isfile(os.path.join(path, filename)):
os.remove(os.path.join(path, filename))
Eu usei o rmque pode forçar a excluir arquivos inexistentes com --preserve-rootcomo uma opção para rm.
--preserve-root
donot remove `/' (default)
rm --help | grep "force"-f,--force ignore nonexistent files and arguments, never prompt
Também podemos usar safe-rm ( sudo apt-get install safe-rm)
O Safe-rm é uma ferramenta de segurança destinada a impedir a exclusão acidental de arquivos importantes, substituindo / bin / rm por um wrapper, que verifica os argumentos fornecidos em uma lista negra configurável de arquivos e diretórios que nunca devem ser removidos.
Primeiro, verifico se o caminho da pasta / arquivo existe ou não. Isso impedirá a configuração da variável fileToRemove /folderToRemove to the string-r / `.
Usar um shell para algo que é trivial é um exagero e essa abordagem também não funciona em várias plataformas (por exemplo, Windows).
Nabla
4
Usar um shell em vez da biblioteca padrão (os.remove por exemplo) é sempre uma das maneiras menos pitônicas / limpas de fazer alguma coisa. Por exemplo, você precisa manipular manualmente os erros retornados pelo shell.
Nabla
1
Eu adicionei minha resposta para usar rmcom segurança e evitar rm -r /. @JonBrave
alper
1
rm -f --preserve-rootnão é bom o suficiente ( --preserve-rootprovavelmente é o padrão de qualquer maneira). Dei -r /como exemplo , e se for -r /homeou o que for? Você provavelmente quer rm -f -- $fileToRemove, mas esse não é o ponto.
JonBrave
3
Não da maneira que você a usou, com um nome de variável (variável de ambiente) e sem aspas e sem proteção. E não para esta pergunta, não. Expor os incautos os.system('rm ...')é extremamente perigoso, desculpe.
unlink
e coloque-a no espaço para nome PHP.Respostas:
Uma maneira mais pitônica seria:
Embora isso exija ainda mais linhas e pareça muito feio, evita a chamada desnecessária
os.path.exists()
e segue a convenção python de excessivas exceções.Pode valer a pena escrever uma função para fazer isso por você:
fonte
os.path.exists()
é executado não significa que ele existe quandoos.remove()
é executado.Prefiro suprimir uma exceção em vez de verificar a existência do arquivo, para evitar um bug do TOCTTOU . A resposta de Matt é um bom exemplo disso, mas podemos simplificá-lo um pouco no Python 3, usando
contextlib.suppress()
:Se
filename
é umpathlib.Path
objeto em vez de uma string, podemos chamar seu.unlink()
método em vez de usaros.remove()
. Na minha experiência, os objetos Path são mais úteis que as strings para manipulação do sistema de arquivos.Como tudo nesta resposta é exclusivo do Python 3, ele fornece mais um motivo para a atualização.
fonte
unlink(2)
, que é de longe a interface relevante mais antiga aqui.except
cláusula, deverá usartry
/except
. Ele não pode ser significativamente reduzido, porque você deve ter uma linha para introduzir o primeiro bloco, o bloco em si, uma linha para introduzir o segundo bloco, e depois que o bloco, de modotry
/except
já é tão concisa quanto possível.os.path.exists
retornaTrue
para pastas e arquivos. Considere usaros.path.isfile
para verificar se o arquivo existe.fonte
No espírito da resposta de Andy Jones, que tal uma autêntica operação ternária:
fonte
Outra maneira de saber se o arquivo (ou arquivos) existe e removê-lo é usando o módulo glob.
O Glob encontra todos os arquivos que poderiam selecionar o padrão com um curinga * nix e faz um loop na lista.
fonte
No Python 3.8, use
missing_ok=True
epathlib.Path.unlink
( docs aqui )fonte
A resposta de Matt é o caminho certo para Pythons mais velhos e Kevin é a resposta certa para os mais novos.
Se você não deseja copiar a função
silentremove
, essa funcionalidade é exposta em path.py como remove_p :fonte
é um one-liner.
Muitos de vocês podem discordar - possivelmente por razões como considerar o uso proposto de ternários "feio" - mas isso levanta a questão de saber se devemos ouvir as pessoas acostumadas a padrões feios quando chamam algo não-padrão de "feio".
fonte
No Python 3.4 ou versão posterior, a maneira pitônica seria:
fonte
Algo assim? Aproveita a avaliação de curto-circuito. Se o arquivo não existir, toda a condicional não poderá ser verdadeira; portanto, o python não incomodará a avaliação da segunda parte.
fonte
Uma oferta do KISS:
E depois:
fonte
Esta é outra solução:
fonte
Outra solução com sua própria mensagem em exceção.
fonte
Eu usei o
rm
que pode forçar a excluir arquivos inexistentes com--preserve-root
como uma opção pararm
.Também podemos usar safe-rm (
sudo apt-get install safe-rm
)Primeiro, verifico se o caminho da pasta / arquivo existe ou não. Isso impedirá a configuração da variável fileToRemove
/
folderToRemoveto the string
-r / `.fonte
rm
com segurança e evitarrm -r /
. @JonBraverm -f --preserve-root
não é bom o suficiente (--preserve-root
provavelmente é o padrão de qualquer maneira). Dei-r /
como exemplo , e se for-r /home
ou o que for? Você provavelmente querrm -f -- $fileToRemove
, mas esse não é o ponto.os.system('rm ...')
é extremamente perigoso, desculpe.