2015-10-06 11 views
6

L'ambito delle variabili create in un'istruzione with si trova all'esterno del blocco with (fare riferimento a: Variable defined with with-statement available outside of with-block?). Ma quando ho eseguito il seguente codice:Perché __del__ viene chiamato alla fine di un blocco con?

class Foo: 
    def __init__(self): 
     print "__int__() called." 

    def __del__(self): 
     print "__del__() called." 

    def __enter__(self): 
     print "__enter__() called." 
     return "returned_test_str" 

    def __exit__(self, exc, value, tb): 
     print "__exit__() called." 

    def close(self): 
     print "close() called." 

    def test(self): 
     print "test() called." 

if __name__ == "__main__": 
    with Foo() as foo: 
     print "with block begin???" 
     print "with block end???" 

    print "foo:", foo # line 1 

    print "-------- Testing MySQLdb -----------------------" 
    with MySQLdb.Connect(host="xxxx", port=0, user="xxx", passwd="xxx", db="test") as my_curs2: 
     print "(1)my_curs2:", my_curs2 
     print "(1)my_curs2.connection:", my_curs2.connection 
    print "(2)my_curs2.connection:", my_curs2.connection 
    print "(2)my_curs2.connection.open:", my_curs2.connection.open # line 2 

L'output mostra che Foo.__del__ si chiama prima di stampare foo (a # line 1 sopra):

__int__() called. 
__enter__() called. 
with block begin??? 
with block end??? 
__exit__() called. 
__del__() called. 
foo: returned_test_str 
-------- Testing MySQLdb ----------------------- 
(1)my_curs2: <MySQLdb.cursors.Cursor object at 0x7f16dc95b290> 
(1)my_curs2.connection: <_mysql.connection open to 'xxx' at 2609870> 
(2)my_curs2.connection: <_mysql.connection open to 'xxx' at 2609870> 
(2)my_curs2.connection.open: 1 

La mia domanda è, perché è Foo.__del__ chiamato qui, se il L'istruzione with non crea un nuovo ambito di esecuzione?

Inoltre, se il metodo della connessione __del__ viene chiamato nel secondo with blocco, io non capisco perché my_curs1.connection è ancora aperta in seguito (vedi # line 2 sopra).

+1

Possibile duplicato di [Posso usare con istruzione con oggetto MySQLdb.Connection?] (Http://stackoverflow.com/questions/11751703/can-i-use-with-statement-with-mysqldb-connection-object) – tzaman

+2

Chengcheng, vedi il link @ tzaman per la risposta al tuo secondo problema e rimuovi quella parte dalla tua domanda. Mantenere un problema in una domanda aiuta a mantenere ordinato StackOverflow e consente alle persone di trovare risposte più rapidamente. Grazie! – CodeMouse92

+1

@ tzaman Questa domanda ha 3 anni e la sua risposta è errata. – Air

risposta

2

È importante notare che foo non è un oggetto di tipo . Creare uno e occorre mantenerlo perché potrebbe contenere informazioni di stato necessarie per chiamare __exit__. Ma una volta fatto, l'oggetto non è necessario e Python è libero di buttarlo via.

In altre parole, questa:

with Foo() as foo: 
    print ('Hello World!') 

è lo stesso di questo:

_bar = Foo() 
foo = _bar.__enter__() 
print ('Hello World!') 
_bar.__exit__() 
del _bar # This will call __del__ because _bar is the only reference 

Il comportamento vi aspettate accadrebbe se foo erano un riferimento alla foo del blocco with. Per esempio ...

class Foo: 
    def __init__(self): 
     print ("__int__() called.") 

    def __del__(self): 
     print ("__del__() called.") 

    def __enter__(self): 
     print ("__enter__() called.") 
     return self # foo now stores the Foo() object 

    def __str__(self): 
     return 'returned_test_str' 

    def __exit__(self, exc, value, tb): 
     print ("__exit__() called.") 

    def close(self): 
     print ("close() called.") 

    def test(self): 
     print ("test() called.") 

if __name__ == "__main__": 
    with Foo() as foo: 
     print ("with block begin???") 
     print ("with block end???") 

    print ("foo:", foo) # line 1 

Stampe

__int__() called. 
__enter__() called. 
with block begin??? 
with block end??? 
__exit__() called. 
foo: returned_test_str 
__del__() called. 

Non ho idea del motivo per cui Connection.__exit__ avrebbe lasciato i suoi cursori aperti comunque.

+0

"con chiusura (auto .__ conn.cursor()) come cur: "" chiamerà close(), ma non __exit __() e __enter __(). Ma con-statement chiamerà __exit __() e __enter __(), ma non close(). Si veda http://stackoverflow.com/questions/5669878/when-to-close-cursors-using-mysqldb – BAE

+0

Mi chiedo solo perché __del __() viene chiamato prima dell'istruzione print (riga1 nel mio post). Ho senso per me se __del __() viene chiamato quando si esce dal programma. – BAE

+0

viene chiamato '__del__' perché non ci sono più riferimenti all'oggetto temporaneo costruito dal blocco' with'. Ricorda, 'pippo' non è il' Foo() 'che hai creato. – QuestionC

Problemi correlati