Nos tempos pré-históricos (Python 1.4), fizemos:
fp = open('filename.txt')
while 1:
line = fp.readline()
if not line:
break
print line
depois do Python 2.1, fizemos:
for line in open('filename.txt').xreadlines():
print line
antes de obtermos o protocolo iterador conveniente no Python 2.3 e poderíamos:
for line in open('filename.txt'):
print line
Eu vi alguns exemplos usando o mais detalhado:
with open('filename.txt') as fp:
for line in fp:
print line
este é o método preferido para a frente?
[edit] Entendo que a instrução with garante o fechamento do arquivo ... mas por que isso não está incluído no protocolo iterador para objetos de arquivo?
python
python-3.x
python-2.7
thebjorn
fonte
fonte
Respostas:
Há exatamente um motivo pelo qual o seguinte é preferido:
Todos nós somos prejudicados pelo esquema relativamente determinístico de contagem de referência do CPython para coleta de lixo. Outras implementações hipotéticas do Python não necessariamente fecham o arquivo "com rapidez suficiente" sem o
with
bloco se eles usarem algum outro esquema para recuperar a memória.Em tal implementação, você pode receber um erro "muitos arquivos abertos" no sistema operacional se o seu código abrir arquivos mais rapidamente do que o coletor de lixo chama finalizadores em identificadores de arquivos órfãos. A solução usual é acionar o GC imediatamente, mas esse é um truque desagradável e deve ser feito por todos os funções que possam encontrar o erro, incluindo as das bibliotecas. Que pesadelo.
Ou você pode simplesmente usar o
with
bloco.Pergunta bônus
(Pare de ler agora se estiver interessado apenas nos aspectos objetivos da pergunta.)
Esta é uma pergunta subjetiva sobre o design da API, por isso tenho uma resposta subjetiva em duas partes.
No nível interno, isso parece errado, porque faz com que o protocolo do iterador faça duas coisas separadas - iterar sobre linhas e feche o identificador do arquivo - e geralmente é uma má idéia fazer uma função de aparência simples executar duas ações. Nesse caso, parece especialmente ruim porque os iteradores se relacionam de maneira quase funcional e baseada em valores com o conteúdo de um arquivo, mas o gerenciamento de identificadores de arquivo é uma tarefa completamente separada. Esmagar os dois, invisivelmente, em uma ação, é surpreendente para os humanos que lêem o código e torna mais difícil raciocinar sobre o comportamento do programa.
Outras línguas chegaram essencialmente à mesma conclusão. Haskell flertou brevemente com o chamado "IO preguiçoso", que permite iterar sobre um arquivo e fechá-lo automaticamente quando você chegar ao final do fluxo, mas é quase universalmente desencorajado o uso de IO preguiçoso em Haskell atualmente e Haskell os usuários passaram para o gerenciamento de recursos mais explícito, como o Conduit, que se comporta mais como o
with
bloco do Python.Em um nível técnico, há algumas coisas que você pode querer fazer com um identificador de arquivo no Python que não funcionaria tão bem se a iteração fechasse o identificador de arquivo. Por exemplo, suponha que eu precise repetir o arquivo duas vezes:
Embora este seja um caso de uso menos comum, considere o fato de que talvez eu tenha adicionado as três linhas de código na parte inferior a uma base de código existente que originalmente possuía as três principais linhas. Se a iteração fechou o arquivo, eu não seria capaz de fazer isso. Portanto, manter a iteração e o gerenciamento de recursos separados facilita a composição de trechos de código em um programa Python maior e funcional.
A composição é um dos recursos de usabilidade mais importantes de um idioma ou API.
fonte
with
dá a você a tranqüilidade, portanto, ainda é uma prática recomendada.Sim,
é o caminho a percorrer.
Não é mais detalhado. É mais seguro.
fonte
se você estiver desativado pela linha extra, poderá usar uma função de invólucro da seguinte forma:
no Python 3.3, a
yield from
declaração tornaria isso ainda mais curto:fonte
fonte