2016-03-15 11 views
8

Provare a eliminare correttamente un oggetto Python. Sto creando un oggetto e quindi presumibilmente lo cancellerò con un'istruzione 'with'. Ma quando faccio una stampa dopo il 'con' affermazione è chiuso .... l'oggetto è ancora lì:Python 'con' non eliminare l'oggetto

class Things(object): 
    def __init__(self, clothes, food, money): 
     self.clothes = clothes 
     self.food = food 
     self.money = money 

    def __enter__(self): 
     return self 

    def __exit__(self, exc_type, exc_val, exc_tb): 
     print('object deleted') 

with Things('socks','food',12) as stuff: 
    greg = stuff.clothes 
    print(greg) 


print(stuff.clothes) 

rendimenti:

socks 
object deleted 
socks 
+3

La risposta di Alex Taylor è giusta sui soldi. Voglio aggiungere che dal momento che Python ha la gestione automatica della memoria (garbage collection) non è necessario preoccuparsi di eliminare oggetti che non sono più in uso. Quindi il tuo uso di un gestore di contesto per questo scopo è inutile. Anche la variabile chiamata "stuff" è creata dall'istruzione 'with' ma continua ad esistere fino alla fine dello script, come hai osservato. Se hai una riga 'del stuff', il nome" stuff "diventa indefinito. È raro che tu debba farlo. –

+1

Possibile duplicato di [Variabile definita con con-statement disponibile al di fuori di con-block?] (Http://stackoverflow.com/questions/6432355/variable-defined-with-with-statement-available-outside-of-with- blocco) –

risposta

5

with chiama il metodo __exit__ di un oggetto su uscendo dall'ambito del blocco. Quello che fa il tuo metodo __exit__ è solo stampare object_deleted. Devi effettivamente inserire il codice per distruggere l'oggetto all'interno del tuo metodo __exit__ (ma nota, questa non è una buona pratica!).

ciò che accade è:

with Things('socks','food',12) as stuff: 
    # the __enter__() method is called and the returned object 
    # is assigned to the variable "stuff" 
    greg = stuff.clothes 
    print(greg) 
# when you've exited the block here, the __exit__() method is called. 

Per quanto riguarda il vostro desiderio di eliminare in modo esplicito l'oggetto, si dovrebbe lasciare al garbage collector di Python. Leggi questo question, ti sarà d'aiuto. Puoi provare a utilizzare gc.collect() o ignorare il metodo __del__. Ecco another good discussion.

+0

Beh, non è corretto al 100%. Non puoi cancellare 'self' dentro' __exit__'. – viraptor

+0

sì, per favore ... in QUESTO caso, mostrami il metodo __exit__ corretto per cancellare un oggetto Things – rikkitikkitumbo

+0

Ho modificato la mia risposta raccomandando all'OP di lasciarlo al garbage collector di Python. –

17

L'istruzione Python with non riguarda l'eliminazione di oggetti, ma la gestione delle risorse. I metodi __enter__ e __exit__ servono per fornire il codice di inizializzazione e distruzione della risorsa, ad esempio, è possibile scegliere di eliminare qualcosa, ma non vi è alcuna eliminazione implicita degli oggetti. Leggi questo with article per capire meglio come usarlo.

L'oggetto rimane nell'ambito dopo l'istruzione with. Potresti chiamare del su di esso se è quello che vuoi. Dal momento che è nell'ambito, puoi interrogarlo dopo che le risorse sottostanti sono state chiuse. Considerate questo codice pseudo:

class DatabaseConnection(object): 
    def __init__(self, connection): 
    self.connection = connection 
    self.error = None 

    def __enter__(self): 
    self.connection.connect() 

    def __exit__(self, exc_type, exc_val, exc_tb): 
    self.connection.disconnect() 

    def execute(self, query): 
    try 
     self.connection.execute(query) 
    except e: 
     self.error = e 

with DatabaseConnection(connection) as db: 
    db.execute('SELECT * FROM DB') 
if db.error: 
    print(db.error) 

del db 

Non vorremmo mantenere una connessione al database in giro più a lungo di quanto abbiamo bisogno (un altro thread/cliente potrebbe averne bisogno), così invece permettiamo la risorsa per essere liberato (implicitamente la fine del blocco with), ma dopo possiamo continuare a interrogare l'oggetto. Ho quindi aggiunto un esplicito del per dire al runtime che il codice è finito con la variabile.

2

Cercando di eliminare correttamente un oggetto Python

Questo è il tuo primo errore, interpretato lingue esplicitamente gratuito è da doversi preoccupare di eliminare gli oggetti per liberare la memoria. Quello che fanno è cancellarli quando non ci sono più riferimenti e l'oggetto non è più in ambito.

Secondo:

with Things('socks','food',12) as stuff: 
    greg = stuff.clothes 
    print(greg) 

Utilizzando una with, nonostante rientro doesn't create a new scope.

contrasto con il codice:

class Things(object): 
    def __init__(self, clothes, food, money): 
     self.clothes = clothes 
     self.food = food 
     self.money = money 

    def __enter__(self): 
     return self 

    def __exit__(self, exc_type, exc_val, exc_tb): 
     print('object deleted') 

stuff = "no stuff" 
def do_it(): 
    with Things('socks','food',12) as stuff: 
     greg = stuff.clothes 
     print(greg) 
     print(stuff) 

do_it() 
print(stuff) 

che dà:

socks 
<__main__.Things object at 0xb744370c> 
object deleted 
no stuff 

Qui l'interno stuff all'interno do_it() non esiste più, in modo che quando il secondo è gestito print(stuff) c'è "no stuff".

In definitiva, non preoccuparti dell'eliminazione di oggetti. Accadrà e non è il tuo lavoro gestirlo.

1

Quindi, grazie a tutti per i buoni collegamenti. Ma volevo davvero eliminare un oggetto e non aspettare il fantastico garbage collector. Questo ha funzionato:

class Things(object): 
    def __init__(self,clothes, food, money): 
     self.clothes = clothes 
     self.food = food 
     self.money = money 

    def __enter__(self): 
     return self 

    def __exit__(self, exc_type, exc_val, exc_tb): 
     print('nothing happens') 



with Things('socks','food',12) as stuff: 
    print(stuff.clothes) 
    del stuff 


print(stuff) 

ora ritorna:

socks 
nothing happens 
Traceback (most recent call last): 
    File "/home/jeff/PycharmProjects/tensorflow_sandbox/main", line 36, in <module> 
    print(stuff) 
NameError: name 'stuff' is not defined 

Evviva! è cancellato

+1

Si potrebbe pensare di avere un 'StuffManager' che ha un metodo' __enter__' che crea e restituisce un oggetto 'Stuff' e un metodo' __exit__' 'lo elimina e usa quella classe nell'istruzione' with'. –