2011-11-09 7 views
7

La funzione di libreria standard open funziona sia come una funzione:Come utilizzare Python chiusura contesto direttore

f = open('file.txt') 
print(type(f)) 
<type 'file'> 

o come un contesto allenatore:

with open('file.txt') as f: 
    print(type(f)) 
<type 'file'> 

Sto cercando di imitare questo comportamento utilizzando contextlib.closing , dove File è il mio file personalizzato classe I/O:

def myopen(filename): 
    f = File(filename) 
    f.open() 
    return closing(f) 

questo funziona come previsto da un contesto allenatore:

with myopen('file.txt') as f: 
    print(type(f)) 
<class '__main__.File'> 

ma ovviamente se chiamo direttamente, torno l'oggetto invece del mio oggetto closing:

f = myopen(filename) 
print(type(f)) 
<class 'contextlib.closing'> 

Quindi, come si implementa myopen in modo che funzioni entrambi come gestore di contesto e restituisce il mio oggetto File quando viene chiamato direttamente?

esempio funzionante completa su github: https://gist.github.com/1352573

+1

Questo non è ciò che 'closing' è per. Si usa 'closing' quando si scrive' with' per trasformare qualsiasi oggetto con un metodo 'close' in un gestore di contesto. Non lo usi prima del tempo. L'esempio [nel 'contextlib' docs] (http://docs.python.org/library/contextlib.html#contextlib.closing) sembra abbastanza chiaro. Se vuoi essere in grado di trasformarlo in un gestore di contesto in qualsiasi momento, la risposta di Zach è corretta. – agf

risposta

13

La cosa più semplice è probabilmente quello di attuare le __enter__ e __exit__ metodi da soli. Qualcosa del genere dovrebbe farlo:

class File(object): 
    # ... all the methods you already have ... 

    # context management 
    def __enter__(self): 
     return self 
    def __exit__(self, *exc_info): 
     self.close() 

Sarebbe, tra l'altro, essere più idiomatico per fare il lavoro del metodo open nel metodo __init__.

+0

Possibile anche: basta eseguire il lavoro 'close' in' __exit__' e fare 'close = __exit__', o viceversa. – agf

+1

+1 per il suggerimento su '__init__' –