2015-10-06 51 views
6

Zakres zmiennych utworzonych w instrukcji with znajduje się poza blokiem with (patrz: Variable defined with with-statement available outside of with-block?). Ale kiedy uruchomić następujący kod:Dlaczego __del__ jest wywoływane na końcu a z blokiem?

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 

Wyjście pokazuje, że Foo.__del__ nazywa się przed wydrukowaniem foo (w # line 1 powyżej):

__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 

Moje pytanie brzmi, dlaczego jest Foo.__del__ nazywane tutaj, jeśli with Instrukcja nie tworzy nowego zakresu wykonywania?

Ponadto, jeśli __del__ metoda połączenia nazywa się w drugiej with bloku, nie rozumiem dlaczego my_curs1.connection jest nadal otwarta później (patrz # line 2 powyżej).

+1

Możliwy duplikat [Czy mogę użyć z instrukcją z obiektem MySQLdb.Connection?] (Http://stackoverflow.com/questions/11751703/can-i-use-with-statement-with-mysqldb-connection-object) – tzaman

+2

Chengcheng, patrz link @ tzaman, aby znaleźć odpowiedź na drugi problem, i usuń tę część ze swojego pytania. Utrzymanie jednego problemu w jednym pytaniu pomaga utrzymać porządek StackOverflow i umożliwia szybsze znajdowanie odpowiedzi. Dziękuję Ci! – CodeMouse92

+1

@tzaman To pytanie ma 3 lata, a jego odpowiedź jest nieprawidłowa. – Air

Odpowiedz

2

Należy pamiętać, że foo nie jest obiektem typu Foo. Tworzysz Foo i musisz go zachować, ponieważ może on zawierać informacje o stanie potrzebne do zadzwonienia pod numer __exit__. Ale kiedy już to zrobisz, obiekt nie jest potrzebny, a Python może go wyrzucić.

Innymi słowy, to:

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

jest taki sam jak ten:

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

Zachowanie spodziewasz się stanie, jeśli foo odniesienie do foo w with bloku. Na przykład ...

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 

Drukuje

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

nie mam pojęcia dlaczego Connection.__exit__ pozostawi otwarte kursory jednak.

+0

" z zamknięciem (self .__ conn.cursor()) jako cur: "" wywoła metodę close(), ale nie __exit __() i __enter __(). Ale instrukcja with-call wywoła funkcje __exit __() i __enter __(), ale nie close(). Proszę zobaczyć http://stackoverflow.com/questions/5669878/when-to-close-cursors-using-mysqldb – BAE

+0

Po prostu zastanawiam się, dlaczego __del __() jest wywoływana przed instrukcją print (linia 1 w moim poście). Mam dla mnie sens, jeśli funkcja __del __() jest wywoływana po wyjściu programu. – BAE

+0

'__del__' jest wywoływane, ponieważ nie ma więcej odwołań do obiektu tymczasowego utworzonego przez blok' with'. Pamiętaj, że 'foo' nie jest' Foo() ', które stworzyłeś. – QuestionC