O fechamento explícito de arquivos é importante?

149

No Python, se você abrir um arquivo sem chamar close()ou fechar o arquivo, mas não usar try- finallyou a withinstrução " ", isso é um problema? Ou é suficiente, como prática de codificação, confiar na coleta de lixo do Python para fechar todos os arquivos? Por exemplo, se alguém fizer isso:

for line in open("filename"):
    # ... do stuff ...

... isso é um problema porque o arquivo nunca pode ser fechado e pode ocorrer uma exceção que impede que seja fechado? Ou será definitivamente fechado na conclusão da fordeclaração porque o arquivo está fora do escopo?

user553702
fonte
13
O arquivo não sai do escopo no final do forbloco. Sua contagem de referência será zero, fazendo com que ela seja fechada automaticamente, mas apenas funções, classes e módulos definem escopos no Python, não outras instruções compostas.
agf
18
Não é um problema, a menos que seja um problema. No nível do sistema operacional, todos os arquivos abertos pelo script serão fechados quando o script sair, portanto, você não precisa se preocupar em fechar arquivos em scripts de ferramentas descartáveis. No entanto, os processos têm um limite no número de arquivos abertos que eles podem manter; portanto, scripts de longa duração ou complexos podem precisar de mais cuidado. De qualquer forma, é um bom hábito fechar seus arquivos.
Russell Borogove
3
@agf: Você está certo que o arquivo não sai do escopo, mas não está relacionado à distinção entre forblocos e funções / classes / módulos. É muito mais simples que isso: objetos não têm escopos, apenas nomes. Não existe um nome que se refira a esse objeto; portanto, não há nada aqui para permanecer no escopo ou sair do escopo.
max
@max Meu comentário está corrigindo sua suposição de que há um escopo associado ao forloop e mencionando que o arquivo é fechado por um motivo completamente diferente. Não entra no escopo do Python, pois não é relevante aqui.
agf
@max há uma referência implícita escopo para que loop for ... este é um argumento de semântica
Peter R

Respostas:

126

No seu exemplo, não é garantido que o arquivo seja fechado antes da saída do intérprete. Nas versões atuais do CPython, o arquivo será fechado no final do loop for porque o CPython usa a contagem de referências como seu mecanismo principal de coleta de lixo, mas esse é um detalhe da implementação, não um recurso do idioma. Outras implementações do Python não são garantidas para funcionar dessa maneira. Por exemplo, IronPython, PyPy e Jython não usam contagem de referência e, portanto, não fecham o arquivo no final do loop.

É uma prática recomendada confiar na implementação da coleta de lixo do CPython, pois isso torna seu código menos portátil. Você pode não ter vazamentos de recursos se usar o CPython, mas se alguma vez mudar para uma implementação Python que não usa contagem de referência, precisará passar por todo o seu código e garantir que todos os seus arquivos estejam fechados corretamente.

Para seu exemplo, use:

with open("filename") as f:
     for line in f:
        # ... do stuff ...
Peter Graham
fonte
8
O uso with open() as ffecha automaticamente o arquivo após a conclusão?
Rohan
24
@ Rohan sim, essa é a pouca mágica que a withdeclaração fornece, mas é claro que, para que essa mágica funcione, o objeto deve ter métodos especiais __enter__e __exit__, neste último, o objeto faz closetodas as outras tarefas de limpeza que precisam ser feitas no momento. fim da withdeclaração ...
Copperfield
1
FYI: Esta resposta explica apenas "quando seria fechada", mas não explica "e se permanecer aberta". Para o último, leia o "O que aconteceria se um arquivo permanecer aberto?" parte desta resposta ( askubuntu.com/questions/701491/… )
RayLuo 22/08/16
Além disso, não fechar arquivos pode resultar em arquivos truncados, pois o conteúdo do arquivo não foi liberado.
Erwan Legrand
Portanto, se eu não fechar o arquivo, recuperarei minha memória com certeza quando o programa parar de ser executado? Ou eu realmente tenho que sair de todo o intérprete?
Pro Q
22

Alguns Pythons fecham arquivos automaticamente quando não são mais referenciados, enquanto outros não, e cabe ao O / S fechar arquivos quando o interpretador Python sair.

Mesmo para os Pythons que fecharão arquivos para você, o tempo não é garantido: pode ser imediatamente ou segundos ou minutos / horas / dias depois.

Portanto, embora você não tenha problemas com o Python que está usando, definitivamente não é uma boa prática deixar seus arquivos abertos. De fato, no cpython 3, você receberá avisos de que o sistema tinha que fechar arquivos para você, se não o fizesse.

Moral: Limpe depois de si mesmo. :)

Ethan Furman
fonte
9
Os arquivos são fechados quando não são mais referenciados no CPython, mas esse não é um recurso de linguagem. Se fosse, você poderia muito bem confiar nele.
Peter Graham
9

Embora seja bastante seguro usar esse construto nesse caso específico, existem algumas ressalvas para generalizar essa prática:

  • run pode potencialmente ficar sem descritores de arquivos, embora improvável, imagine caçar um bug como esse
  • talvez você não consiga excluir o arquivo em alguns sistemas, por exemplo, win32
  • se você executar algo diferente de CPython, não saberá quando o arquivo será fechado para você
  • se você abrir o arquivo no modo de gravação ou leitura / gravação, não saberá quando os dados serão liberados
Dima Tisnek
fonte
3

O arquivo é coletado e, portanto, fechado. O GC determina quando é fechado, não você. Obviamente, essa não é uma prática recomendada, pois você pode atingir o limite de manipulação de arquivos abertos se não fechar os arquivos assim que terminar de usá-los. E se, dentro desse forciclo, você abrir mais arquivos e deixá-los persistentes?

Nam Nguyen
fonte
Mas se você abriu outros arquivos nesse loop for, ainda seria possível que houvesse mais de um arquivo aberto simultaneamente, se você fecha explicitamente algum deles ou não. Você está dizendo que o arquivo não é necessariamente coletado como lixo assim que sai do escopo; portanto, seria fechado mais cedo se fosse feito explicitamente? E quando ocorre uma exceção (quando você usa com / try-finalmente vs. não faz isso)?
user553702
1
No CPython, a contagem de referência fará com que ela seja coletada após a forinstrução - você não precisará esperar pela próxima execução da coleta de lixo.
agf
3

Oi É muito importante fechar o descritor de arquivo na situação em que você usará o conteúdo no mesmo script python. Hoje eu próprio percebo depois de tanto tempo detectando a depuração. O motivo é que o conteúdo será editado / removido / salvo somente depois que você fechar o descritor de arquivo e as alterações forem afetadas no arquivo!

Então, suponha que você tenha a situação de gravar conteúdo em um novo arquivo e, sem fechar o fd, esteja usando esse arquivo (não o fd) em outro comando shell que lê seu conteúdo. Nesta situação, você não obterá o conteúdo do comando shell conforme o esperado e, se você tentar depurar, não poderá encontrar o bug facilmente. você também pode ler mais na minha entrada do blog http://magnificentzps.blogspot.in/2014/04/importance-of-closing-file-descriptor.html

Zeel Shah
fonte
1

Durante o processo de E / S, os dados são armazenados em buffer: isso significa que eles são mantidos em um local temporário antes de serem gravados no arquivo.

O Python não libera o buffer - isto é, grava dados no arquivo - até ter certeza de que você terminou de escrever. Uma maneira de fazer isso é fechar o arquivo.

Se você gravar em um arquivo sem fechar, os dados não chegarão ao arquivo de destino.

Sanket Nagrale
fonte