I dettagli diventano un po 'tecnico, quindi cominciamo con la versione semplice:
Alcuni tipi sanno essere utilizzato in un comunicato with
. Gli oggetti file, come quello che si ottiene da open
, sono un esempio di questo tipo. Come risulta, gli oggetti che torni da urllib.request.urlopen
, sono anche un esempio di tale tipo, quindi il tuo secondo esempio potrebbe essere scritto allo stesso modo del primo.
Ma alcuni tipi non sanno come essere utilizzati in un'istruzione with
.La funzione closing
è progettata per racchiudere questi tipi, purché abbiano un metodo close
, chiamerà il loro metodo close
quando si esce dall'istruzione with
.
Naturalmente alcuni tipi non sanno come essere utilizzato in una dichiarazione with
, e, inoltre, non può essere utilizzato con closing
perché il loro metodo di pulitura non è nominato close
(o perché li pulizia è più complicata di un semplice chiudendoli). In tal caso, è necessario scrivere un gestore di contesto personalizzato. Ma anche questo non è solitamente così difficile.
In termini tecnici:
Una dichiarazione with
richiede un context manager, un oggetto con __enter__
e __exit__
metodi. Chiamerà il metodo __enter__
e fornirà il valore restituito da tale metodo nella clausola as
e chiamerà quindi il metodo __exit__
alla fine dell'istruzione with
.
oggetti File ereditano da io.IOBase
, che è un manager contesto cui __enter__
metodo stesso ritorna, e la cui __exit__
chiamate self.close()
.
L'oggetto restituito dal urlopen
è (assumendo un URL http
o https
) un HTTPResponse
, che, come dicono i documenti, "può essere utilizzato con un'istruzione with
".
La funzione closing
:
Return un manager contesto che chiude cosa al termine del blocco. Questo è fondamentalmente equivalente a:
@contextmanager
def closing(thing):
try:
yield thing
finally:
thing.close()
Non è sempre chiaro al 100% nella documentazione, che tipi sono responsabili di contesto e quali tipi non sono. Soprattutto dal momento che c'è stata una grande spinta da 3.1 a trasformare tutto ciò che potrebbe essere un gestore di contesto in uno (e, se è per questo, a rendere tutto ciò che è per lo più simile a un file in un vero IOBase
se ha senso), ma non è ancora Completato al 100% a partire dal 3.4.
Si può sempre provare e vedere. Se ottieni uno AttributeError: __exit__
, l'oggetto non è utilizzabile come gestore di contesto. Se pensi che dovrebbe essere, presenta un bug che suggerisce la modifica. Se non ricevi questo errore, ma i documenti non menzionano che è legale, presenta un bug che suggerisce l'aggiornamento dei documenti.
Stavo per suggerire che qualcuno dovrebbe archiviare un bug di documenti su 'contextlib' per questo, e che se non sei tu chiunque dovrebbe accreditarti ... ma prima che potessi finire, Martijn ha già archiviato il bug, con il link qua dietro. :) – abarnert