2015-10-06 14 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

चेंग्चेग, अपने दूसरे मुद्दे के उत्तर के लिए @ tzaman का लिंक देखें, और उस हिस्से को अपने प्रश्न से हटा दें। एक मुद्दे को एक प्रश्न में रखते हुए StackOverflow को साफ रखने में मदद मिलती है और लोगों को अधिक तेज़ी से उत्तर ढूंढने में सक्षम बनाता है। धन्यवाद! – CodeMouse92

+1

@tzaman वह प्रश्न 3 साल का है और इसका उत्तर गलत है। – Air

उत्तर

2

यह ध्यान रखना महत्वपूर्ण है कि fooFoo प्रकार का ऑब्जेक्ट नहीं है। आप Foo बनाते हैं और इसे चारों ओर रखने की आवश्यकता है क्योंकि इसमें __exit__ पर कॉल करने के लिए आवश्यक राज्य जानकारी हो सकती है। लेकिन एक बार ऐसा करने के बाद, ऑब्जेक्ट अनियंत्रित होता है और पायथन इसे फेंकने के लिए स्वतंत्र होता है।

दूसरे शब्दों में, यह:

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 

व्यवहार आप होगा यदि foowith ब्लॉक के 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

" बंद होने के साथ (स्वयं .__ conn।कर्सर()) cur के रूप में: "" करीबी() को कॉल करेगा, लेकिन __exit __() और __enter __() नहीं। लेकिन साथ-कथन __exit __() और __enter __() को कॉल करेगा, लेकिन बंद नहीं होगा()। कृपया http://stackoverflow.com/questions/5669878/when-to-close-cursors-using-mysqldb – BAE

+0

मुझे आश्चर्य है कि __del __() को प्रिंट स्टेटमेंट (मेरी पोस्ट में लाइन 1) से पहले क्यों कहा जाता है। अगर मुझे प्रोग्राम से बाहर निकलने पर __del __() कहा जाता है तो मुझे समझ में आता है। – BAE

+0

'__del__' कहा जा रहा है क्योंकि 'ब्लॉक' द्वारा निर्मित अस्थायी वस्तु का कोई और संदर्भ नहीं है। याद रखें, 'foo' आपके द्वारा बनाई गई' Foo() 'नहीं है। – QuestionC

संबंधित मुद्दे