2015-10-06 4 views
6

Объем переменных, созданных в операторе with, находится за пределами блока with (см .: Variable defined with with-statement available outside of with-block?). Но когда я запускаю следующий код:Почему __del__ вызывается в конце блока с блоком?

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 

Выходные данные показывают, что Foo.__del__ вызывается перед печатью Foo (в # line 1 выше):

__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 

Мой вопрос, почему Foo.__del__ называют здесь, если Оператор with не создает новую область выполнения?

Кроме того, если __del__ метод данного соединения называется во втором with блоке, я не понимаю, почему my_curs1.connection все еще открыт после (см # line 2 выше).

+1

Возможный дубликат [Можно ли использовать с инструкцией с объектом MySQLdb.Connection?] (Http://stackoverflow.com/questions/11751703/can-i-use-with-statement-with-mysqldb-connection-object) – tzaman

+2

Chengcheng, см. Ссылку @ tzaman для ответа на ваш второй вопрос и удалить эту часть из вашего вопроса. Сохранение одной проблемы в одном вопросе помогает сохранить StackOverflow в порядке и позволяет быстрее находить ответы. Спасибо! – CodeMouse92

+1

@tzaman Этот вопрос составляет 3 года, и его ответ неверен. – Air

ответ

2

Важно отметить, что foo - не объект типа Foo. Вы создаете файл Foo и должны его поддерживать, потому что он может содержать информацию о состоянии, необходимую для вызова __exit__. Но как только это будет сделано, объект будет ненужным, и Python сможет его выбросить.

Другими словами, это:

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

То же самое, как это:

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

поведение вы ожидаете, что произойдет, если foo были ссылки на обув в with блока. Например ...

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 

Печать

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

Я понятия не имею, почему Connection.__exit__ бы оставить свои курсоры открытыми, однако.

+0

" с закрытием (self .__ conn.cursor()) как cur: "" вызовет close(), но не __exit __() и __enter __(). Но with-statement будет вызывать __exit __() и __enter __(), но не close(). См. Http://stackoverflow.com/questions/5669878/when-to-close-cursors-using-mysqldb – BAE

+0

Мне просто интересно, почему __del __() вызывается перед оператором печати (строка1 в моем сообщении). Имею смысл для меня, если __del __() вызывается при выходе программы. – BAE

+0

'__del__' вызывается, потому что больше нет ссылок на временный объект, построенный блоком' with'. Помните, что 'foo' не является' Foo() 'вы сделали. – QuestionC