2015-10-06 51 views
6

with語句中創建的變量範圍在with塊之外(請參閱:Variable defined with with-statement available outside of with-block?)。但是,當我運行下面的代碼:爲什麼__del__在with塊的結尾被調用?

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__在打印富前(以上爲# 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

誠誠,請參閱@ 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塊的foo的引用會發生的行爲。例如...

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())as cur:「」將調用close(),但不會調用__exit __()和__enter __()。但是with-statement會調用__exit __()和__enter __(),但不能關閉()。請參閱http://stackoverflow.com/questions/5669878/when-to-close-cursors-using-mysqldb – BAE

+0

我只是想知道爲什麼__del __()在打印語句(我的文章中的line1)之前調用。如果在程序退出時調用__del __(),我對我有意義。 – BAE

+0

'__del__'被調用,因爲不再有對'with'塊構造的臨時對象的引用。記住,'foo'不是你所做的'Foo()'。 – QuestionC

相關問題