2009-09-03 12 views
10

Per leggere il contenuto di un file:File aperto: questo cattivo stile Python?

data = open(filename, "r").read() 

Il file aperto immediatamente smette fatto riferimento ovunque, quindi l'oggetto file alla fine chiuso ... e non dovrebbe influenzare altri programmi di usarlo, in quanto il file è aperto solo per leggere, non per scrivere.

EDIT: Questo mi ha effettivamente morso in un progetto che ho scritto - mi ha spinto a chiedere this domanda. Gli oggetti file vengono ripuliti solo quando si esaurisce la memoria, non quando si esauriscono gli handle di file. Quindi, se lo fai troppo spesso, potresti finire a corto di descrittori di file e causare i tuoi tentativi di IO di aprire i file per generare eccezioni.

+3

Si noti che questo leggerà l'intero file in memoria, non importa quanto sia grande. Quindi assicurati che sia un file che puoi gestire. Oltre a questo, sono d'accordo con le risposte. – balpha

+0

@balpha: Ma le risposte sono in conflitto. ;) (Presumo che abbiate fatto il commento prima che tutte le risposte fossero in). –

risposta

29

Solo per la cronaca: Questo è solo leggermente più lungo, e chiude il file immediatamente:

from __future__ import with_statement 

with open(filename, "r") as f: 
    data = f.read() 
+4

+1 Ho aggiunto 'import' nel caso in cui stiano usando Python 2.5 :) –

+0

Una domanda in stile followup: è davvero orribile fare * con open (" t1.py "," r ") come f: f. leggi() * tutto su una riga? So che non è leggibile, ma così spesso, la lettura del file è una cosa molto semplice, e il prossimo che legge il codice non si preoccupa davvero di come lo hai fatto. –

+0

@Jenn D: Un punto del 'con' è di limitare tutta l'elaborazione in un ambito ordinato. Mettendo 'con open() come f: f.read()' in una linea tipo di sconfitte lo scopo dell'ambito di 'with'. –

3

No, è perfettamente ragionevole lo stile Python IMO, secondo il vostro ragionamento.

Aggiornamento: Ci sono molti commenti qui se gli oggetti file vengono riordinati immediatamente o no. Piuttosto che speculare, ho fatto qualche ricerca. Ecco quello che vedo:


da un commento in object.h di Python:

le macro Py_INCREF (op) e Py_DECREF (op) vengono utilizzati per incrementare o conteggi dei riferimenti decremento. Py_DECREF chiama deallocatore dell'oggetto funzione quando il refcount scende a 0

Guardando in fileobject.c di Python:

La tabella di funzione per il file oggetti punti per funzionare file_dealloc. Questa funzione chiama close_the_file, che a sua volta chiude il file.


Quindi sembra ragionevole affermare che al momento, su CPython, quando non ci sono più riferimenti a un oggetto file, , viene chiuso senza alcun ritardo. Se ritieni che questa interpretazione sia errata, pubblica un commento che indichi perché ti senti in quel modo.

+0

È ragionevole, ma le risorse del sistema operativo potrebbero non essere del tutto disponibili come vorreste. Ad esempio, provare a rimuovere il file subito dopo averlo letto potrebbe non funzionare perché le risorse del sistema operativo sono trattenute da librerie C sottostanti, anche se l'oggetto 'file' di Python è stato sottoposto a garbage collection. Fino a quando il sistema operativo non pensa che il file non sia più in uso, potresti non essere in grado di eliminarlo. –

+0

@ S. Lott: stai dicendo che un oggetto 'file' garbage-collected non viene chiuso (in modo che il sistema operativo sappia che non è più in uso)? Mi aspetterei * che la cancellazione di un oggetto file richiuda il file, ma non riesco a trovare nulla nella documentazione. – EOL

+5

La mia comprensione è che CPython (l'implementazione di riferimento che la maggior parte delle persone pensa di quando pensano a Python) in realtà distrugge tutti gli oggetti senza riferimento mentre lasciano l'ambito. In tal caso, l'oggetto file lascia l'ambito non appena l'operazione read() viene completata. Quindi dovrebbe fare esattamente quello che vuoi. Questo non è un comportamento garantito, comunque. Altre implementazioni di Python (Jython credo sia un ottimo esempio) possono gestire diversamente la garbage collection. Il mio istinto è di usare la semplice implementazione se sai che stai usando CPython e non ti interessa la portabilità. –

1

mi sembra soddisfacente .. Ho letto spesso file simili.

6

È vero che alla fine si chiuderà, ma alla fine potrebbe non essere abbastanza presto. Soprattutto se lo stai utilizzando all'interno di un ciclo, il sistema potrebbe esaurire gli handle di file prima che il GC raggiunga gli oggetti del file.

+0

oh, non ci ho mai pensato! – Claudiu

+0

Ma se il fileobj è conteggiato conteggio .. va direttamente a 0 e viene cancellato immediatamente? In CPython (?). – u0b34a0f6ae

+0

@ kaizer.se: non è ancora necessariamente eliminato immediatamente. solo quando CPython ha bisogno di più memoria. – Claudiu

4

Il codice funziona esattamente come dici tu lo fa, ma è comunque un cattivo stile. Il tuo codice si basa su ipotesi che potrebbero essere vere ora, ma non sempre saranno vere. Non è impossibile che il tuo codice venga eseguito in una situazione in cui il file che si sta aprendo e non si chiude fa materia. Vale veramente la pena rischiare solo per salvare 1 o 2 righe di codice? Io non la penso così

2

anche se funziona come previsto, penso che non riesce in due conteggi:

  1. Il codice non scalare senza soluzione di continuità, in quanto si sta leggendo l'intero file in memoria, e questo può o non può essere necessariamente quello che vuoi
  2. Secondo lo Zen di Python (prova import this nel prompt di Python per recuperarlo) "esplicito è meglio di implicito" e, non riuscendo a chiudere esplicitamente il file, potresti confondere qualcuno che, in fondo alla strada, sarà lasciato con il tuo codice per la manutenzione.

Aiuta davvero essere espliciti! Python incoraggia lo stile esplicito.

Oltre a questo, per uno script usa e getta, il tuo stile ha un senso.

Forse approfitterete di this answer.

Problemi correlati