apri leggi e chiudi un file in 1 riga di codice


128

Adesso uso:

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

Ma per migliorare l'aspetto del codice, posso fare:

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

Quando si utilizza la sintassi sopra, come si chiude il file per liberare risorse di sistema?


19
Non c'è nulla di intrinsecamente più attraente in una linea. Il codice viene letto molto più spesso di quanto sia scritto e dovrebbe essere scritto per la comprensione, non per la "freddezza". L'unica eccezione è quando esiste un linguaggio ben noto in una lingua, ma in questo caso non ne sono consapevole.
drdwilcox,

17
@drdwilcox: One-liner criptici sono cattivi, one-liner dichiarativi sono buoni. Non vi è alcun motivo (almeno non riesco a vederne uno), perché non esiste un wrapper di funzione nel core per leggere un file (tale necessità comune) in una singola chiamata di funzione. Qualcosa del genere contents = os.readfile(path). Se volessi fare qualcosa di più elaborato, allora ok, lo userei felicemente with open(path) as fd: contents = fd.read(). Naturalmente si può scrivere il proprio wrapper, ma è a questo che serve il core, per fornire l'utilità alle astrazioni ai programmatori.
tokland,

5
È vero che il codice viene letto molto più di quanto sia scritto, ma l'implicazione che un codice più lungo è altrettanto valido del codice corto non potrebbe essere più sbagliata. Se investi tempo nel rendere il tuo codice il più breve possibile (senza ricorrere a trucchi intelligenti che sono difficili da capire), quell'investimento pagherà ripetutamente quando il codice viene letto. Ogni riga che scrivi è un disservizio per chiunque legga il tuo codice, quindi dovresti cercare di scrivere il meno possibile. Ricorda la famosa citazione di Pascal: "Ho allungato questa lettera solo perché non ho avuto il tempo di abbreviarla".
John Williams,

Risposte:


195

Non è necessario chiuderlo: Python lo farà automaticamente durante la garbage collection o all'uscita dal programma. Ma come ha notato @delnan, è meglio chiuderlo esplicitamente per vari motivi.

Quindi, cosa puoi fare per mantenerlo breve, semplice ed esplicito:

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

Ora sono solo due righe e piuttosto leggibili, credo.


2
@ 1qazxsw2 Se si utilizza l' withistruzione, la risorsa file verrà chiusa correttamente.
David Alber,

13
Re prima frase: Python lo chiuderà alla fine . Ma ciò non significa che dovresti dimenticare di chiudere. Anche con il refounting, il file può rimanere aperto molto più a lungo di quanto si pensi e si desideri (ad esempio se si fa riferimento a cicli). Questo vale tre volte nelle implementazioni di Python che hanno un GC decente, dove non hai alcuna garanzia che qualcosa sia GC'd in un determinato momento. Anche la documentazione di CPython dice che non dovresti fare affidamento su GC per la pulizia in questo modo. L'ultima parte della risposta dovrebbe essere in grassetto.

6
Se hai davvero bisogno di un liner , è possibile mettere il output = f.read()pezzo sulla stessa linea dopo il :.
Karl Knechtel,

1
"apri leggi e chiudi un file in 1 riga di codice" si tratta di due righe e non risponde alla domanda.
user5359531

1
Dipende dall'implementazione - vedi la risposta di Sven.
Tim Pietzcker,

71

Il modulo Pathlib della libreria standard Python fa quello che stai cercando:

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

Non dimenticare di importare 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'

Su Python 27 installare backported pathlibopathlib2


8
Le altre risposte che propongono withvanno bene, ma withè un'affermazione, non un'espressione. Questa pathlibrisposta è l'unica risposta alla domanda originale che può essere incorporata in un'espressione Python. Qualcosa di simileSECRET_KEY = os.environ.get('SECRET_KEY') or pathlib.Path('SECRET_KEY').read_bytes()
LeoRochael

24

Usando CPython, il tuo file verrà chiuso immediatamente dopo l'esecuzione della linea, poiché l'oggetto file viene immediatamente raccolto in modo errato. Ci sono due svantaggi, però:

  1. Nelle implementazioni Python diverse da CPython, il file spesso non viene immediatamente chiuso, ma piuttosto in un secondo momento, al di fuori del tuo controllo.

  2. In Python 3.2 o versioni successive, verrà generato un ResourceWarning, se abilitato.

Meglio investire una linea aggiuntiva:

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

Ciò assicurerà che il file sia chiuso correttamente in tutte le circostanze.


17

Non è necessario importare alcuna libreria speciale per farlo.

Usa la sintassi normale e aprirà il file per la lettura, quindi lo chiuderà.

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

o

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

che ti dà un array x contenente le linee e può essere stampato in questo modo:

for line in x: print line

Questi one-liner sono molto utili per la manutenzione, in pratica sono autodocumentati.


8

Quello che puoi fare è usare l' withistruzione e scrivere i due passaggi su una riga:

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

L' withistruzione avrà cura di chiamare la __exit__funzione dell'oggetto dato anche se nel tuo codice è successo qualcosa di brutto; è vicino alla try... finallysintassi. Per l'oggetto restituito da open, __exit__corrisponde alla chiusura del file.

Questa affermazione è stata introdotta con Python 2.6.


Piccolo chiarimento: secondo la documentazione è with stato introdotto in Python 2.5, ma doveva essere importato esplicitamente da __future__. È diventato disponibile da tutti i contesti in Python 2.6.
David Alber,

5

usa ilio : (inline io):

solo una chiamata di funzione invece del file open (), read (), close ().

from ilio import read

content = read('filename')

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

4
In che modo differisce dalle prime 3 risposte?
Tutti i lavoratori sono essenziali il

4
La differenza più grande è che è solo una riga come la domanda specificata. Personalmente non riesco a trovare oltre a questo, ma mi sento libero di criticare il mio lavoro piuttosto che contribuire effettivamente alla domanda da soli.

3
Il modo più breve e integrato per ottenere l'apertura, la lettura e la chiusura di un file in Python consiste nell'utilizzare 2 righe logiche, a prescindere che siano condensate o meno a 1 riga. Quindi non vedo che questa risposta sia effettivamente diversa dalle 3 risposte originali.
Tutti i lavoratori sono essenziali il

1
Non importa se è "efficace" diverso. Sono arrivato a questa pagina cercando la sintassi a una riga che potrebbe essere utilizzata con python -cla riga di comando, quindi pubblicare risposte a 2 righe non aiuta.
user5359531

1
@ user5359531 Non vedo il tuo punto: sai che puoi citare espressioni python con ", usare ;per aggiungere due istruzioni ed eliminare newline dopo :? L'espressione seguente funziona bene per me:$> python -c "with open('some file', 'r') as f: print(next(f))"
Joël,

2

Penso che il modo più naturale per raggiungere questo obiettivo sia definire una funzione.

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

Quindi è possibile effettuare le seguenti operazioni:

output = read('pagehead.section.htm')

0

Faccio spesso una cosa del genere quando devo inserire alcune righe intorno a qualcosa che ho inserito in un file di registro:

$ 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

1
Completamente estranei al tema originale, ma si dovrebbe guardare in grep -A <n>, grep -B <n>e grep -C <n>, se è utile. Ulteriori informazioni: stackoverflow.com/a/9083/1830159
Liam Stanley

0

Utilizzando more_itertools.with_iter, è possibile aprire, leggere, chiudere e assegnare un equivalente outputin una riga (esclusa la dichiarazione di importazione):

import more_itertools as mit


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

Per quanto possibile, cercherei un altro approccio diverso dall'assegnare il contenuto di un file a una variabile, cioè un'iterazione lenta - questo può essere fatto usando un withblocco tradizionale o nell'esempio sopra rimuovendo join()e iterando output.


Puoi importare anche all'interno dell'eliner. "".join(line for line in __import__('more_itertools').with_iter(open("pagehead.section.htm", "r")))Funziona bene ed elimina la necessità di una riga per l'importazione.
melwil,

1
Sono completamente d'accordo con voi. Tuttavia, mentre discutevo di risolvere compiti con gli oneliner, mi sono spesso trovato in argomenti in cui il risultato concordato dovrebbe essere una singola riga di codice incollata in una nuova shell di pitone. Tali sfide raramente si conformano a pep8. Non è in alcun modo una buona pratica per scrivere codice, era inteso solo come un suggerimento per eliminare la necessità di importare.
melwil,

0

Se vuoi quella sensazione calda e sfocata basta andare con .

Per python 3.6 ho eseguito questi due programmi con un nuovo inizio di IDLE, dando runtime di:

0.002000093460083008  Test A
0.0020003318786621094 Test B: with guaranteed close

Quindi non c'è molta differenza.

#--------*---------*---------*---------*---------*---------*---------*---------*
# 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

PRODUZIONE:

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

PRODUZIONE:

OK, starting program...
--- 0.0020003318786621094 seconds ---
OK, program execution has ended.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.