2015-10-06 11 views
6

Der Gültigkeitsbereich der in einer with-Anweisung erstellten Variablen liegt außerhalb des with Blocks (siehe: Variable defined with with-statement available outside of with-block?). Aber wenn ich den folgenden Code ausführen:Warum wird __del__ am Ende eines with-Blocks aufgerufen?

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 

Die Ausgabe zeigt, dass Foo.__del__ vor dem Drucken foo genannt wird (bei # line 1 oben):

__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 

Meine Frage ist, warum ist Foo.__del__ hier genannt wird, wenn die with Anweisung erstellt keinen neuen Ausführungsbereich?

Auch wenn die __del__ der Verbindungsmethode in dem zweiten with Block genannt wird, verstehe ich nicht, warum my_curs1.connection nachher noch offen ist (# line 2 siehe oben).

+1

Mögliche Duplikate von [Kann ich mit Anweisung mit MySQLdb.Connection-Objekt verwenden?] (Http://stackoverflow.com/questions/11751703/cani-i-use-with-statement-with-mysqldb-connection-object) – tzaman

+2

Chengcheng, siehe @ Tzaman Link für die Antwort auf Ihre zweite Frage, und entfernen Sie diesen Teil von Ihrer Frage. Wenn Sie ein Problem auf eine Frage beschränken, bleibt StackOverflow aufgeräumt und die Benutzer können schneller Antworten finden. Vielen Dank! – CodeMouse92

+1

@tzaman Diese Frage ist 3 Jahre alt und ihre Antwort ist falsch. – Air

Antwort

2

Es ist wichtig zu beachten, dass foo kein Objekt vom Typ Foo ist. Sie erstellen ein Foo und müssen es beibehalten, da es möglicherweise Statusinformationen enthält, die zum Aufrufen von __exit__ erforderlich sind. Aber sobald das erledigt ist, wird das Objekt nicht benötigt und Python ist frei, es wegzuwerfen.

anders gesagt, dies:

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

ist die gleiche wie folgt aus:

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

Das Verhalten, das Sie passieren würde erwarten, wenn foo ein Verweis auf die foo with Blocks waren. Zum Beispiel ...

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 

Drucke

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

Ich habe keine Ahnung, warum Connection.__exit__ seine Cursor jedoch offen lassen würde.

+0

" mit closing (self .__ conn.cursor()) als cur: "" ruft close() auf, aber nicht __exit __() und __enter __(). Aber with-Anweisung ruft __exit __() und __enter __() auf, aber nicht close(). Bitte sehen Sie http://StackOverflow.com/Questions/5669878/When-To-Close-Cursors-using-Mysqldb – BAE

+0

Ich frage mich nur, warum __del __() vor print-Anweisung (line1 in meinem Beitrag) aufgerufen wird. Ich mache Sinn für mich, wenn __del __() beim Beenden des Programms aufgerufen wird. – BAE

+0

'__del__' wird aufgerufen, weil es keine Referenzen mehr auf das temporäre Objekt gibt, das mit dem' with' -Block erstellt wurde. Denken Sie daran, 'foo' ist nicht das' Foo() ', das Sie gemacht haben. – QuestionC

Verwandte Themen