abrir ler e fechar um arquivo em 1 linha de código

128

Agora eu uso:

pageHeadSectionFile = open('pagehead.section.htm','r')
output = pageHeadSectionFile.read()
pageHeadSectionFile.close()

Mas, para tornar o código melhor, eu posso fazer:

output = open('pagehead.section.htm','r').read()

Ao usar a sintaxe acima, como fecho o arquivo para liberar recursos do sistema?

1qazxsw2
fonte
19
Não há nada inerentemente mais atraente em one-liners. O código é lido com muito mais frequência do que está escrito e deve ser escrito para compreensão, não para "frescura". A única exceção é quando existe um idioma conhecido em um idioma, mas não conheço um neste caso.
Drdwilcox
17
@drdwilcox: one-liners crípticos são ruins, one-liners declarativos são bons. Não há motivo (pelo menos não consigo ver um), por que não há um invólucro de função no núcleo para ler um arquivo (necessidade tão comum) em uma única chamada de função. Algo como contents = os.readfile(path). Se eu quisesse fazer algo mais sofisticado, ok, eu usaria feliz with open(path) as fd: contents = fd.read(). É claro que se pode escrever seu próprio wrapper, mas é para isso que serve o núcleo, para fornecer as abstrações úteis aos programadores.
tokland
5
É verdade que o código é lido muito mais do que escrito, mas a implicação de que um código mais longo é tão bom quanto um código curto não poderia estar mais errado. Se você investir tempo em tornar seu código o mais curto possível (sem recorrer a truques inteligentes que são difíceis de entender), esse investimento será recompensado repetidamente quando o código for lido. Cada linha que você escreve é ​​um desserviço para quem lê seu código; portanto, você deve escrever o mínimo possível. Lembre-se da famosa citação de Pascal: "Eu prolongei esta carta apenas porque não tive tempo de encurtá-la".
John Williams

Respostas:

195

Você realmente não precisa fechá-lo - o Python o fará automaticamente durante a coleta de lixo ou na saída do programa. Mas, como observou @delnan, é uma prática recomendada fechá-lo explicitamente por vários motivos.

Então, o que você pode fazer para mantê-lo breve, simples e explícito:

with open('pagehead.section.htm','r') as f:
    output = f.read()

Agora são apenas duas linhas e bem legíveis, eu acho.

Tim Pietzcker
fonte
2
@ 1qazxsw2 Se você usar a withinstrução, o recurso de arquivo será fechado corretamente para você.
David Alber
13
Primeira frase: Python o fechará eventualmente . Mas isso não significa que você deva esquecer o fechamento. Mesmo com refcounting, o arquivo pode permanecer aberto por muito mais tempo do que você pensa e deseja (por exemplo, se for mencionado por ciclos). Isso acontece três vezes em implementações Python que possuem um GC decente, em que você não tem garantia de que algo seja GC em um determinado momento. Até a documentação do CPython diz que você não deve confiar no GC para limpeza como esta. A última parte da resposta deve estar em negrito.
6
Se você realmente precisa de uma linha , é possível colocar a output = f.read()peça na mesma linha após a :.
precisa
1
"abrir ler e fechar um arquivo em 1 linha de código" são duas linhas e não respondem à pergunta.
User5359531 31/05
1
Isso depende da implementação - veja a resposta de Sven.
Tim Pietzcker
71

O módulo Pathlib da Biblioteca Padrão do Python faz o que você procura:

Path('pagehead.section.htm').read_text()

Não se esqueça de importar o Path:

jsk@dev1:~$ python3
Python 3.5.2 (default, Sep 10 2016, 08:21:44)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from pathlib import Path
>>> (Path("/etc") / "hostname").read_text()
'dev1.example\n'

No Python 27, instale o backport pathliboupathlib2

Janusz Skonieczny
fonte
8
As outras respostas propostas withsão boas, mas withsão uma afirmação, não uma expressão. Esta pathlibresposta é a única resposta à pergunta original que pode ser incorporada em uma expressão Python. Algo comoSECRET_KEY = os.environ.get('SECRET_KEY') or pathlib.Path('SECRET_KEY').read_bytes()
LeoRochael
24

Usando o CPython, seu arquivo será fechado imediatamente após a execução da linha, porque o objeto do arquivo é imediatamente coletado como lixo. Existem duas desvantagens:

  1. Nas implementações Python diferentes do CPython, o arquivo geralmente não é fechado imediatamente, mas posteriormente, além do seu controle.

  2. No Python 3.2 ou superior, isso gerará um ResourceWarning, se ativado.

Melhor investir uma linha adicional:

with open('pagehead.section.htm','r') as f:
    output = f.read()

Isso garantirá que o arquivo seja fechado corretamente em todas as circunstâncias.

Sven Marnach
fonte
17

Não há necessidade de importar nenhuma biblioteca especial para fazer isso.

Use a sintaxe normal e ele abrirá o arquivo para leitura e depois o fechará.

with open("/etc/hostname","r") as f: print f.read() 

ou

with open("/etc/hosts","r") as f: x = f.read().splitlines()

que fornece uma matriz x contendo as linhas e pode ser impressa da seguinte forma:

for line in x: print line

Essas one-liners são muito úteis para manutenção - basicamente auto-documentadas.

SDsolar
fonte
8

O que você pode fazer é usar a withinstrução e escreva as duas etapas em uma linha:

>>> with open('pagehead.section.htm', 'r') as fin: output = fin.read();
>>> print(output)
some content

A withinstrução cuidará de chamar a __exit__função do objeto fornecido, mesmo que algo de ruim tenha acontecido no seu código; está perto da try... finallysintaxe. Para o objeto retornado por open, __exit__corresponde ao fechamento do arquivo.

Esta declaração foi introduzida no Python 2.6.

Joël
fonte
Pequenos esclarecimentos: de acordo com a documentação with foi introduzida no Python 2.5, mas teve que ser explicitamente importada do __future__. Tornou-se disponível em todos os contextos no Python 2.6.
precisa
5

use ilio : (inline io):

apenas uma chamada de função em vez de abrir o arquivo (), ler (), fechar ().

from ilio import read

content = read('filename')
iman
fonte
2
with open('pagehead.section.htm')as f:contents=f.read()

fonte
4
Como isso difere das 3 principais respostas?
Todos os trabalhadores têm Essencial
4
A maior diferença é que há apenas uma linha conforme a pergunta especificada. Pessoalmente, não consigo encontrar nada além disso, mas sinta-se à vontade para criticar meu trabalho, em vez de realmente contribuir para a pergunta.
3
A maneira mais curta e interna de conseguir abrir, ler e fechar um arquivo no Python é usar duas linhas lógicas, condensadas em uma linha ou não. Portanto, não acho que essa resposta seja diferente das três respostas originais.
Todos os trabalhadores são essenciais
1
Não importa se é "efetivamente" diferente. Cheguei a esta página procurando uma sintaxe de uma linha que possa ser usada python -cna linha de comando, portanto, publicar respostas em duas linhas não ajuda.
User5359531
1
@ user5359531 Não entendo o seu ponto: você sabe que pode citar expressões python com ", use ;para acrescentar duas instruções e excluir nova linha depois :? A seguinte expressão funciona muito bem para mim: #$> python -c "with open('some file', 'r') as f: print(next(f))"
Jo Jo
2

Eu acho que a maneira mais natural de conseguir isso é definir uma função.

def read(filename):
    f = open(filename, 'r')
    output = f.read()
    f.close()
    return output

Então você pode fazer o seguinte:

output = read('pagehead.section.htm')
Adrien Pavao
fonte
0

Freqüentemente faço algo assim quando preciso obter algumas linhas em torno de algo que recebi em um arquivo de log:

$ grep -n "xlrd" requirements.txt | awk -F ":" '{print $1}'
54

$ python -c "with open('requirements.txt') as file: print ''.join(file.readlines()[52:55])"
wsgiref==0.1.2
xlrd==0.9.2
xlwt==0.7.5
Matthew Purdon
fonte
1
Completamente alheios ao tema original, mas você deve olhar para grep -A <n>, grep -B <n>e grep -C <n>, se ele é útil. Mais informações: stackoverflow.com/a/9083/1830159
Liam Stanley
0

Usando more_itertools.with_iter, é possível abrir, ler, fechar e atribuir um equivalente outputem uma linha (excluindo a declaração de importação):

import more_itertools as mit


output = "".join(line for line in mit.with_iter(open("pagehead.section.htm", "r")))

Embora possível, eu procuraria outra abordagem além de atribuir o conteúdo de um arquivo a uma variável, ou seja, iteração lenta - isso pode ser feito usando um withbloco tradicional ou no exemplo acima, removendo join()e iterando output.

pylang
fonte
Você também pode importar dentro do oneliner. "".join(line for line in __import__('more_itertools').with_iter(open("pagehead.section.htm", "r")))Isso funciona muito bem e elimina a necessidade de uma linha para a importação.
melwil
1
Eu concordo completamente com você. No entanto, ao discutir a resolução de tarefas com oneliners, muitas vezes me encontrei em argumentos em que o resultado acordado deveria ser uma única linha de código colada em um novo shell python. Tais desafios raramente estão em conformidade com o pep8. Não é uma boa prática para escrever código, foi apenas uma dica para remover a necessidade de importações.
melwil
0

Se você quer aquele sentimento quente e confuso, vá em frente .

Para o python 3.6, executei esses dois programas sob um novo começo do IDLE, fornecendo tempos de execução de:

0.002000093460083008  Test A
0.0020003318786621094 Test B: with guaranteed close

Portanto, não há muita diferença.

#--------*---------*---------*---------*---------*---------*---------*---------*
# Desc: Test A for reading a text file line-by-line into a list
#--------*---------*---------*---------*---------*---------*---------*---------*

import sys
import time

#                                  # MAINLINE
if __name__ == '__main__':
    print("OK, starting program...")

    inTextFile = '/Users/Mike/Desktop/garbage.txt'

#                                  # Test: A: no 'with;
    c=[]
    start_time = time.time()
    c = open(inTextFile).read().splitlines()
    print("--- %s seconds ---" % (time.time() - start_time))

    print("OK, program execution has ended.")
    sys.exit()                     # END MAINLINE

RESULTADO:

OK, starting program...
--- 0.002000093460083008 seconds ---
OK, program execution has ended.

#--------*---------*---------*---------*---------*---------*---------*---------*
# Desc: Test B for reading a text file line-by-line into a list
#--------*---------*---------*---------*---------*---------*---------*---------*

import sys
import time

#                                  # MAINLINE
if __name__ == '__main__':
    print("OK, starting program...")

    inTextFile = '/Users/Mike/Desktop/garbage.txt'

#                                  # Test: B: using 'with'
    c=[]
    start_time = time.time()
    with open(inTextFile) as D: c = D.read().splitlines()
    print("--- %s seconds ---" % (time.time() - start_time))

    print("OK, program execution has ended.")
    sys.exit()                     # END MAINLINE

RESULTADO:

OK, starting program...
--- 0.0020003318786621094 seconds ---
OK, program execution has ended.
CopyPasteIt
fonte