2012-01-18 11 views
6

मेरे पास एक कक्षा है जो लेखन के लिए एक फ़ाइल खोलती है।डेल माईक्लास ऑब्जेक्ट को कॉल नहीं करता है .__ del __()

class MyClass: 
    def __del__(self): 
     self.close() 

    def close(self): 
     if self.__fileHandle__ is not None: 
       self.__fileHandle__.close() 

लेकिन जब मैं की तरह कोड के साथ वस्तु को हटा दें::

myobj = MyClass() 
myobj.open() 
del myobj 

अगर मैं वस्तु reinstantiate करने की कोशिश, मैं एक मूल्य त्रुटि मिलती है मेरी नाशक में, मैं समारोह है कि फाइल बंद कर देता है फोन :

ValueError: The file 'filename' is already opened. Please close it before reopening in write mode. 

जबकि अगर मैं फोन myobj.close()del myobj इससे पहले कि मैं इस समस्या को नहीं मिलता है। तो __del__() क्यों नहीं बुलाया जा रहा है?

+1

'ऑब्जेक्ट 'से विरासत का प्रयास करें - ऐसा नहीं करना कुछ छः वर्षों के लिए पुरानी शैली माना जाता है। – Marcin

+0

आपको कुछ और कोड दिखाना चाहिए। यह कैसे बता सकता है कि कैसे myobj.close() 'चीजों को बदलता है, यह जानने के बिना कि यह क्या करता है? – ugoren

+1

ध्यान रखें कि 'del' '__del__' को कॉल नहीं करता है। यह सिर्फ एक संदर्भ को हटा देता है। आमतौर पर संदर्भ प्रबंधक प्रोटोकॉल ('स्टेटमेंट के साथ 'का उपयोग करके स्पष्ट रूप से बंद करना बेहतर होता है। – yak

उत्तर

8

क्या आप वाकई __del__ का उपयोग करना चाहते हैं? issues__del__ और कचरा संग्रह के साथ हैं।

class MyClass(object): 
    def __enter__(self): 
     return self 
    def __exit__(self,ext_type,exc_value,traceback): 
     if self.__fileHandle__ is not None: 
       self.__fileHandle__.close() 

ऐसा करके, आप MyClass इस तरह इस्तेमाल कर सकते हैं:

आप एक context manager बजाय MyClass बना सकता है

with MyClass() as myobj: 
    ... 

और myobj.__exit__ (और इस प्रकार self.__fileHandle__.close()) जब अजगर पत्ते बुलाया जाएगा with-block

+0

+1 मुद्दों का उल्लेख करने के लिए। http://docs.python.org/library/gc.html#gc.garbage का कहना है कि «ऑब्जेक्ट्स जिनमें __del __() विधियां हैं और संदर्भ चक्र का हिस्सा हैं, पूरे संदर्भ चक्र को अचयनित करने का कारण बनता है, जिसमें वस्तुओं को जरूरी नहीं है चक्र लेकिन केवल इससे पहुंच योग्य। » –

+0

मुझे नहीं लगता कि ओपी के उदाहरण में संदर्भ चक्र कैसा है। एक वस्तु है, यह 'del''d हो जाता है, और '__del __()' कॉल नहीं किया जाता है। – sudo

+1

इसके अलावा, मेरी स्थिति में, मैं जीसी हैंडल सामान को छोड़ दूंगा क्योंकि इसे तुरंत बंद करने की ज़रूरत नहीं है, अंततः ... लेकिन इसमें हमेशा समस्याएं होती हैं। और नहीं, संदर्भ प्रबंधक वास्तविक समाधान नहीं हैं। वे आपको उसी फ़ंक्शन कॉल के भीतर ऑब्जेक्ट को बंद करने के लिए प्रतिबंधित करते हैं और हर बार जब आप एक का उपयोग करते हैं तो अपने कोड को एक स्तर पर इंडेंट करते हैं। जब मैं इनमें से 20 बनाना चाहता हूं तो इसे अपठनीय बनाता है। – sudo

8

यह नहीं है कि del क्या करता है। यह दुर्भाग्यपूर्ण है कि __del__ का नाम del है, क्योंकि वे एक-दूसरे से संबंधित नहीं हैं। आधुनिक शब्दावली में, __del__ विधि को फ़ाइनलाइज़र कहा जाएगा, विनाशक नहीं और अंतर महत्वपूर्ण है।

कम अंतर यह है कि यह गारंटी करने के लिए जब एक नाशक कहा जाता है आसान है, लेकिन आप जब __del__ बुलाया जाएगा के बारे में बहुत कुछ गारंटी देता है और यह कभी नहीं कहा जा हो सकता है। ऐसी कई अलग-अलग परिस्थितियां हैं जो इसका कारण बन सकती हैं।

यदि आप लेक्सिकल स्कॉपिंग चाहते हैं, तो with कथन का उपयोग करें। अन्यथा, सीधे myobj.close() पर कॉल करें। del कथन केवल संदर्भों को हटा देता है, वस्तुओं नहीं।

मुझे एक और प्रश्न (link) एक अलग प्रश्न के लिए मिला जो अधिक जानकारी में इसका उत्तर देता है। यह दुर्भाग्यपूर्ण है कि उस प्रश्न के स्वीकृत उत्तर में गंभीर त्रुटियां हैं।

संपादित करें: टिप्पणीकर्ताओं के अनुसार, आपको object से उत्तराधिकारी होना चाहिए। यह ठीक है, लेकिन यह अभी भी संभव है कि __del__ कभी नहीं कहा जाएगा (आप भाग्यशाली हो सकते हैं)। उपरोक्त लिंक देखें।

2

आपका कोड object से प्राप्त होना चाहिए - ऐसा नहीं करना कम से कम छह वर्षों के लिए तारीख से बाहर (विशेष मामलों को छोड़कर) माना जाता है।

आप के बारे में __del__ यहाँ पढ़ सकते हैं: http://docs.python.org/reference/datamodel.html#object.del

का कारण है कि आप object से विरासत की जरूरत लघु संस्करण है कि __del__ नई शैली कक्षाओं पर केवल "जादू" है।

यदि आपको अंतिमकर्ता की कॉलिंग पर भरोसा करने की आवश्यकता है, तो मैं दृढ़ता से सुझाव देता हूं कि आप अन्य उत्तरों में अनुशंसित संदर्भ प्रबंधक दृष्टिकोण का उपयोग करें, क्योंकि यह एक पोर्टेबल, मजबूत समाधान है।

+1

आह ने अभी एक उदाहरण पाया जहां यह "जादू" काम नहीं करता है ... इसके बजाय ipython का उपयोग कर। – tdc

+0

@tdc: जब तक मैं गलत नहीं हूं, ipython cpython पर आधारित है। किसी भी मामले में, यदि आप किसी विशेष उदाहरण के व्यवहार पर भरोसा करते हैं, तो आपका कोड गैर-पोर्टेबल होगा। अन्य उत्तरों में अनुशंसित संदर्भ प्रबंधक दृष्टिकोण का उपयोग करना शायद बेहतर होगा। – Marcin

0

शायद कुछ और इसका संदर्भ दे रहा है, यही कारण है कि __del__ को अभी तक नहीं कहा जा रहा है (अभी तक)।

#!/usr/bin/env python 

import time 

class NiceClass(): 
    def __init__(self, num): 
     print "Make %i" % num 
     self.num = num 
    def __del__(self): 
     print "Unmake %i" % self.num 

x = NiceClass(1) 
y = NiceClass(2) 
z = NiceClass(3) 
lst = [x, y, z] 
time.sleep(1) 
del x 
del y 
del z 
time.sleep(1) 
print "Deleting the list." 
del lst 
time.sleep(1) 

यह NiceClass की __del__ उदाहरणों फोन नहीं करता है जब तक हम सूची उन्हें संदर्भ हटा दें:

इस कोड पर विचार करें।

सी ++ के विपरीत, __del__ मांग पर वस्तु को नष्ट करने के लिए बिना शर्त कहा जा रहा है। जीसी चीजों को थोड़ा कठिन बनाता है। यहां कुछ जानकारी दी गई है: http://arctrix.com/nas/python/gc/

+0

इस मामले में निश्चित रूप से केवल एक संदर्भ था – tdc

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