2015-05-07 3 views
7

So che è una buona abitudine usare close per chiudere un file se non più usato in Python. Ho provato ad aprire un gran numero di file aperti e non a chiuderli (nello stesso processo Python), ma non vedo eccezioni o errori. Ho provato sia Mac che Linux. Quindi, mi chiedo solo se Python è abbastanza intelligente da gestire l'handle del file per chiuderlo/riutilizzarlo automaticamente, in modo che non ci sia bisogno di preoccuparsi della chiusura dei file?su chiudi un file in Python

grazie in anticipo, Lin

+5

Quando ci pensi equivale a "Se dimentico di segnalare quando guido non ho * ancora * avuto un incidente, quindi dovrei smettere di usare i miei indicatori?" - solo perché tu di solito *** fai sesso con qualcosa non lo rende una buona idea. –

risposta

19

pitone saranno, in generale, immondizia raccogliere oggetti non più in uso e non si fa riferimento. Ciò significa che è del tutto possibile che gli oggetti file aperti, che corrispondono ai filtri del garbage collector, vengano ripuliti e probabilmente chiusi. Tuttavia; Non si dovrebbe fare affidamento su questo, e di utilizzare invece:

with open(..): 

Esempio (anche le migliori pratiche):

with open("file.txt", "r") as f: 
    # do something with f 

NB: Se non si chiudere il file e lasciate "descrittori di file aperti" in giro sul vostro sistema, alla fine inizierete a colpire i limiti di risorse sul vostro sistema; specificamente "ulimit". Alla fine inizierai a vedere gli errori del sistema operativo relativi a "troppi file aperti". (Presumendo Linux qui, ma altri sistemi operativi avranno un comportamento simile).

Importante: E 'anche una buona praticaa chiudere i file aperti che hai scritto anche, in modo che i dati che hai scritto è corretto arrossato. Ciò aiuta a garantire l'integrità dei dati e non i file contengono inaspettatamente dati danneggiati a causa di un arresto anomalo dell'applicazione.

Vale la pena notare che la nota importante di cui sopra è la causa di molti problemi con cui si scrive in un file; rileggilo; scopri che è vuoto; ma poi chiudi il tuo programma python; leggerlo in un editor di testo e rendersi conto che non è vuoto.

Demo: Un buon esempio del tipo di limiti delle risorse e degli errori che potrebbero colpire se non assicurarsi di chiudere il file aperto (s):

$ python 
Python 2.7.6 (default, Mar 22 2014, 22:59:56) 
[GCC 4.8.2] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> xs = [open("/dev/null", "r") for _ in xrange(100000)] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
IOError: [Errno 24] Too many open files: '/dev/null' 
+0

Questa è una buona informazione, correlata, ma non sono sicuro che risponda alla domanda "_why_ devo chiudere i file?" – GreenAsJade

+0

Perché? Perché esiste un limite del sistema operativo sul numero di file aperti contemporaneamente. Questo non è necessariamente colpa di Python. Detto questo, tutti i file aperti da un programma vengono chiusi dal sistema operativo al termine del programma, quindi a volte puoi farla franca chiudendoli in quel modo. –

+0

Nessuno ha detto che è "colpa di Python". :) –

3

Si ha bisogno di chiudere i file (output) in Python.

Un esempio del motivo è quello di scaricare l'output su di essi. Se non si chiudono correttamente i file e il programma viene ucciso per qualche motivo, il file aperto a sinistra può essere danneggiato.

Inoltre, v'è questo: Why python has limit for count of file handles?

2

E 'una buona idea gestire la chiusura del file. Non è il genere di cose che darà errori ed eccezioni: corrompe i file, o non scrive ciò che hai provato a scrivere, e così via.

L'interprete python più comune, CPython, che probabilmente stai utilizzando, fa, tuttavia, prova a gestire il file chiudendo in modo intelligente, nel caso in cui non lo fai. Se apri un file, e poi viene raccolto del garbage, che generalmente accade quando non ci sono più riferimenti ad esso, CPython chiuderà il file.

Così, per esempio, se si dispone di una funzione come

def write_something(fname): 
    f = open(fname, 'w') 
    f.write("Hi there!\n") 

poi Python saranno generalmente chiudere il file ad un certo punto, dopo la funzione ritorna.

Che non è poi così male per le situazioni semplici, ma considerare questo:

def do_many_things(fname): 

    # Some stuff here 

    f = open(fname, 'w') 
    f.write("Hi there!\n") 

    # All sorts of other stuff here 

    # Calls to some other functions 

    # more stuff   

    return something 

Ora avete aperto il file, ma potrebbe essere molto tempo prima della sua chiusura. Su alcuni sistemi operativi, ciò potrebbe significare che altri processi non saranno in grado di aprirlo. Se le altre cose hanno un errore, il tuo messaggio potrebbe non essere effettivamente scritto sul file. Se stai scrivendo un bel po 'di cose, alcune potrebbero essere scritte, e alcune parti potrebbero non esserlo; se stai modificando un file, potresti causare tutti i tipi di problemi. E così via.

Una domanda interessante da considerare, tuttavia, è se, nei sistemi operativi in ​​cui i file possono essere aperti per la lettura da più processi, c'è un rischio significativo di aprire un file per leggerlo e non chiuderlo.

+0

* Python chiuderà generalmente il file dopo che la funzione è tornata * - Sei sicuro? Non deve raccogliere dati sull'eliminazione della funzione. –

+0

Mi riferisco solo a CPython; dovrebbe chiudersi dopo il ritorno della funzione se questo rimuove l'ultimo riferimento ad esso, che sarebbe nel semplice esempio. – cge

3

Ci sono due buoni motivi.

  1. Se il programma si arresta in modo anomalo o viene interrotto in modo imprevisto, i file di output potrebbero essere danneggiati.
  2. È buona norma chiudere ciò che si apre.
5

Per aggiungere al James Mills' answer, se avete bisogno di capire il motivo specifico non vedi eventuali errori:

Python definisce che, quando un file viene garbage collection, verrà chiusa automaticamente. Ma Python lascia all'implementazione come vuole gestire la garbage collection. CPython, l'implementazione che stai probabilmente usando, lo fa con il conteggio dei riferimenti: non appena l'ultimo riferimento ad un oggetto scompare, viene immediatamente raccolto. Quindi, tutti questi apparirà a lavorare in CPython:

def spam(): 
    for i in range(100000): 
     open('spam.txt') # collected at end of statement 

def eggs(): 
    for i in range(100000): 
     f = open('eggs.txt') # collected next loop, when f is reassigned 

def beans(): 
    def toast(): 
     f = open('toast.txt') # collected when toast exits 
    for i in range(100000): 
     toast() 

Ma molte altre implementazioni (tra cui l'altro tre grandi, PyPy, Jython e IronPython) utilizzare netturbini più intelligenti che rilevano spazzatura al volo , senza dover tenere traccia di tutti i riferimenti. Ciò li rende più efficienti, migliori nel threading, ecc., Ma significa che non è deterministico quando un oggetto viene raccolto. Quindi lo stesso codice non funzionerà. Oppure, peggio, funzionerà nei tuoi 60 test, e poi fallirà non appena stai facendo una demo per i tuoi investitori.

Sarebbe un peccato se avessi bisogno della velocità di PyPy o dell'integrazione .NET di IronPython, ma non potevi averlo senza riscrivere tutto il tuo codice. O se qualcun altro voleva usare il tuo codice, ma aveva bisogno che funzionasse in Jython, e doveva cercare altrove.


Nel frattempo, anche in CPython, l'interprete non raccoglie tutti i suoi rifiuti in caso di arresto. (Sta migliorando, ma anche nel 3.4 non è perfetto.Quindi, in alcuni casi, stai facendo affidamento sul sistema operativo per chiudere i tuoi file per te. Il sistema operativo sarà di solito svuotalo quando lo fa, ma forse non se tu, ad es., Li avessi aperti in un thread daemon, o sei uscito con os._exit o segfault. (E, naturalmente, sicuramente non se si è usciti da qualcuno inciampare il cavo di alimentazione.)


Infine, anche CPython (dal 3,3, credo) ha un codice specifico per generare avvisi se si lascia che i tuoi file siano garbage collection invece di chiuderli. Questi avvisi sono disattivati ​​per impostazione predefinita, ma le persone propongono regolarmente di accenderli e un giorno potrebbe accadere.