Respostas:
A resposta para essa pergunta depende um pouco da implementação específica do Python.
Para entender do que se trata, preste atenção especial ao file
objeto real . No seu código, esse objeto é mencionado apenas uma vez, em uma expressão, e fica inacessível imediatamente após o read()
retorno da chamada.
Isso significa que o objeto do arquivo é lixo. A única pergunta restante é "Quando o coletor de lixo coletará o objeto de arquivo?".
no CPython, que usa um contador de referência, esse tipo de lixo é percebido imediatamente e, portanto, será coletado imediatamente. Isso geralmente não é verdade para outras implementações python.
Uma solução melhor, para garantir que o arquivo esteja fechado, é este padrão:
with open('Path/to/file', 'r') as content_file:
content = content_file.read()
que sempre fechará o arquivo imediatamente após o término do bloco; mesmo se ocorrer uma exceção.
Edit: Para colocar um ponto mais fino nele:
Diferente de file.__exit__()
, que é "automaticamente" chamado em uma with
configuração de gerenciador de contexto, a única outra maneira que file.close()
é automaticamente chamada (ou seja, que não seja explicitamente chamada por si mesmo) é via file.__del__()
. Isso nos leva à questão de quando é __del__()
chamado?
Um programa gravado corretamente não pode assumir que os finalizadores serão executados a qualquer momento antes do encerramento do programa.
- https://devblogs.microsoft.com/oldnewthing/20100809-00/?p=13203
Em particular:
Os objetos nunca são explicitamente destruídos; no entanto, quando se tornam inacessíveis, podem ser coletados no lixo. É permitido que uma implementação adie a coleta de lixo ou a omita por completo - é uma questão de qualidade da implementação como a coleta de lixo é implementada, desde que nenhum objeto seja coletado que ainda esteja acessível.
[...]
Atualmente, o CPython usa um esquema de contagem de referência com detecção atrasada (opcional) de lixo vinculado ciclicamente, que coleta a maioria dos objetos assim que eles se tornam inacessíveis, mas não é garantido coletar lixo contendo referências circulares.
- https://docs.python.org/3.5/reference/datamodel.html#objects-values-and-types
(Ênfase minha)
mas, como sugere, outras implementações podem ter outro comportamento. Como exemplo, o PyPy possui 6 implementações diferentes de coleta de lixo !
__exit__()
nesses casos parece uma falha de design.
try
/ finally
complicado e a inutilidade altamente comum dos manipuladores de limpeza que with
resolvem. A diferença entre "fechar explicitamente" e "gerenciar com with
" é que o manipulador de saída é chamado mesmo se uma exceção for lançada. Você pode incluir close()
uma finally
cláusula, mas isso não é muito diferente de usar with
, um pouco mais confuso (3 linhas extras em vez de 1) e um pouco mais difícil de acertar.
with foo() as f: [...]
é basicamente o mesmo que f = foo()
, f.__enter__()
[...] e f.__exit__()
com exceções manipuladas , de modo que __exit__
é sempre chamado. Portanto, o arquivo sempre é fechado.
Você pode usar o pathlib .
Para Python 3.5 e superior:
from pathlib import Path
contents = Path(file_path).read_text()
Para versões mais antigas do Python, use pathlib2 :
$ pip install pathlib2
Então:
from pathlib2 import Path
contents = Path(file_path).read_text()
Esta é a read_text
implementação real :
def read_text(self, encoding=None, errors=None):
"""
Open the file in text mode, read it, and close the file.
"""
with self.open(mode='r', encoding=encoding, errors=errors) as f:
return f.read()
Bem, se você precisar ler o arquivo linha por linha para trabalhar com cada linha, poderá usar
with open('Path/to/file', 'r') as f:
s = f.readline()
while s:
# do whatever you want to
s = f.readline()
Ou ainda melhor:
with open('Path/to/file') as f:
for line in f:
# do whatever you want to
Em vez de recuperar o conteúdo do arquivo como uma única sequência, pode ser útil armazenar o conteúdo como uma lista de todas as linhas que o arquivo compreende :
with open('Path/to/file', 'r') as content_file:
content_list = content_file.read().strip().split("\n")
Como pode ser visto, é necessário adicionar os métodos concatenados .strip().split("\n")
à resposta principal neste tópico .
Aqui, .strip()
apenas remove os caracteres de espaço em branco e nova linha nas terminações de toda a cadeia de arquivos e .split("\n")
produz a lista real dividindo a cadeia de arquivos inteira em cada caractere de nova linha \ n .
Além disso, dessa forma, todo o conteúdo do arquivo pode ser armazenado em uma variável, o que pode ser desejado em alguns casos, em vez de fazer um loop sobre o arquivo linha por linha, como apontado nesta resposta anterior .