2014-11-22 9 views
6

I gestori del contesto definiscono le funzioni di installazione/pulizia __enter__ e __exit__. Eccezionale. Voglio mantenerne uno come variabile membro. Quando il mio oggetto di classe esce dal campo di applicazione, voglio eseguire questa pulizia. Questo è fondamentalmente il comportamento che capisco accade automaticamente con costruttori/distruttori C++.Variabile membro gestita dal contesto Python?

class Animal(object): 

    def __init__(self): 
     self.datafile = open("file.txt") # This has a cleanup function 
     # I wish I could say something like... 
     with open("file.txt") as self.datafile: # uh... 

    def makeSound(self): 
     sound = self.datafile # I'll be using it later 

# Usage... 
if True: 
    animal = Animal() 
# file should be cleaned up and closed at this point. 

risposta

1

Python non fa C++ - Raii stile ("Resource acquisizione è di inizializzazione", che significa tutto ciò che si acquista nel costruttore, si rilascia nel distruttore). In effetti, quasi no lingue oltre a C++ do C++ - RAII di stile. manager contesto di Python e with dichiarazioni sono una diverso modo per ottenere la stessa cosa che C++ fa con Raii, e che la maggior parte altre lingue che fare con finally dichiarazioni, guard dichiarazioni, ecc (Python ha anche finally, naturalmente.)


Che cosa intendi esattamente per "Quando il mio oggetto di classe esce dall'ambito"?

Gli oggetti non escono dall'ambito; riferimenti (o variabili, o nomi, qualunque cosa tu preferisca). Qualche tempo dopo che l'ultimo riferimento non rientra nello scope (per CPython, questo è immediatamente, a meno che non sia coinvolto in un ciclo di riferimento, per altre implementazioni, di solito non lo è), l'oggetto sarà raccolto in modo improprio.


Se si vuole fare un po 'di pulizia in cui gli oggetti sono garbage collection, si utilizza il metodo __del__ per questo. Ma raramente è quello che vuoi veramente. (In realtà, alcune classi hanno un metodo __del__ solo per avvertire gli utenti che si sono dimenticati di pulire, piuttosto che per pulire silenziosamente.)


Una soluzione migliore è quella di rendere Animalstesso un manager contesto, in modo che possa gestire altri gestori di contesto o semplicemente gestire le cose in modo esplicito. Poi si può scrivere:

if True: 
    with Animal() as animal: 
     # do stuff 
    # now the file is closed 

Ecco un esempio:

class Animal(object): 

    def __init__(self): 
     self.datafile = open("file.txt") 

    def __enter__(self): 
     return self 

    def __exit__(self, type, value, traceback): 
     self.datafile.close() 

    def makeSound(self): 
     sound = self.datafile # I'll be using it later 

(Basta cadere alla fine del __exit__ come questo significa che, dopo aver chiamato self.datafile.close(), siamo riusciti a fare nulla se non ci fosse un'eccezione, o re-raise la stessa eccezione se ci fosse uno. Quindi, non c'è bisogno di scrivere nulla esplicito per realizzare questo obiettivo.)


Ma di solito, se si sta andando per trasformare una classe in un gestore di contesto, devi anche aggiungere un esplicito close. Proprio come fanno i file. E una volta fatto ciò, non è necessario rendere Animal in un gestore di contesto; puoi semplicemente usare closing.

2

mi danno lezioni di una funzione close se ha senso e quindi utilizzare il manager closing contesto:

class MyClass(object): 
    def __init__(self): 
     self.resource = acquire_resource() 

    def close(): 
     release_resource(self.resource) 

E poi utilizzarlo come:

from contextlib import closing 

with closing(MyClass()) as my_object: 
    # use my_object 
Problemi correlati