__Del__ विधि क्या है, इसे कैसे कॉल करें?


108

मैं एक कोड पढ़ रहा हूं। एक वर्ग है जिसमें __del__विधि को परिभाषित किया गया है। मुझे पता चला कि इस पद्धति का उपयोग कक्षा की एक आवृत्ति को नष्ट करने के लिए किया जाता है। हालाँकि, मुझे कोई ऐसा स्थान नहीं मिला जहाँ इस पद्धति का उपयोग किया गया हो। इसका मुख्य कारण यह है कि मुझे नहीं पता कि इस पद्धति का उपयोग कैसे किया जाता है, शायद ऐसा नहीं है obj1.del():। तो, मेरे सवाल यह है कि __del__विधि को कैसे कॉल किया जाए ?

जवाबों:


168

__del__एक फाइनल है । यह तब कहा जाता है जब किसी वस्तु को कचरा एकत्र किया जाता है जो किसी बिंदु पर तब होता है जब ऑब्जेक्ट के सभी संदर्भ हटा दिए जाते हैं।

एक साधारण मामले में यह सही हो सकता है जब आप कहते हैं del xया, यदि xफ़ंक्शन समाप्त होने के बाद, एक स्थानीय चर है। विशेष रूप से, जब तक कि परिपत्र संदर्भ नहीं होते हैं, तब तक CPython (मानक पायथन कार्यान्वयन) तुरंत कचरा इकट्ठा करेगा।

हालाँकि, यह CPython का कार्यान्वयन विवरण है। पायथन कचरा संग्रहण की एकमात्र आवश्यक संपत्ति यह है कि यह सभी संदर्भों को हटाए जाने के बाद होता है, इसलिए यह आवश्यक नहीं हो सकता है कि ठीक बाद में हो और ऐसा बिल्कुल न हो

इससे भी अधिक, चर कई कारणों से लंबे समय तक रह सकते हैं , जैसे कि एक प्रचार अपवाद या मॉड्यूल आत्मनिरीक्षण चर संदर्भ गणना को 0. से अधिक रख सकता है। इसके अलावा, चर संदर्भों के चक्र का एक हिस्सा हो सकता है - कचरे के संग्रह के साथ सीपीथॉन सबसे अधिक बार टूट जाता है , लेकिन सभी नहीं, इस तरह के चक्र, और फिर भी केवल समय-समय पर।

चूंकि आपके पास कोई गारंटी नहीं है कि इसे निष्पादित किया गया है, इसलिए किसी को उस कोड को कभी भी नहीं रखना चाहिए जिसे आपको चलाने की आवश्यकता है __del__()- इसके बजाय, यह कोड ब्लॉक finallyके tryखंड या एक संदर्भ प्रबंधक के withबयान में आता है। हालाँकि, इसके लिए वैध उपयोग के मामले हैं __del__: उदाहरण के लिए यदि कोई ऑब्जेक्ट Xसंदर्भ Yऔर Yएक वैश्विक cache( cache['X -> Y'] = Y) में संदर्भ की एक प्रति भी रखता है, तो X.__del__कैश प्रविष्टि को हटाने के लिए भी विनम्र होगा ।

यदि आप जानते हैं कि विध्वंसक एक आवश्यक सफाई प्रदान करता है (उपरोक्त दिशानिर्देश के उल्लंघन में), तो आप इसे सीधे कॉल करना चाह सकते हैं , क्योंकि विधि के रूप में इसके बारे में कुछ खास नहीं है x.__del__():। जाहिर है, आपको ऐसा तभी करना चाहिए जब आपको पता हो कि दो बार फोन करने का मन नहीं करता। या, एक अंतिम उपाय के रूप में, आप इस पद्धति का उपयोग करके इसे फिर से परिभाषित कर सकते हैं

type(x).__del__ = my_safe_cleanup_method  

5
आप कहते हैं कि CPython की विशेषता यह है कि किसी वस्तु को तुरंत हटाने के बाद उसकी संदर्भ संख्या शून्य हो जाती है, "कार्यान्वयन विवरण" है। मैं आश्वस्त नहीं हूँ। क्या आप उस दावे का लिंक प्रदान कर सकते हैं? (मेरा मतलब है, बोल्ड फ़ॉन्ट है अपने आप ही सुंदर कायल है, लेकिन लिंक एक करीबी दूसरा रहे हैं ... :-)
स्टुअर्ट बर्ग

14
CPython कार्यान्वयन विवरण: CPython वर्तमान में एक संदर्भ-गणना योजना का उपयोग करता है, जिसमें (वैकल्पिक) चक्रवात से जुड़े कचरे का पता लगाने में देरी होती है, ... अन्य कार्यान्वयन अलग तरीके से कार्य करते हैं और CPython बदल सकते हैं। ( docs.python.org/2/reference/datamodel.html )
ilya n।

__exit__इस संदर्भ में क्या है? क्या इसे बाद या पहले __del__या साथ में चलाया जाता है?
Lony

1
जब कार्यक्रम समाप्त हो जाता है, तो क्या "बिल्कुल नहीं हो सकता है" में शामिल है?
एंडी हेडन

1
@AndyHayden: __del__कार्यक्रम समाप्ति पर भी विधियाँ नहीं चल सकती हैं, और यहाँ तक कि जब वे समाप्ति पर दौड़ते हैं, तो एक ऐसी __del__विधि लिखना जो ठीक से काम करते हुए भी हो, जबकि दुभाषिया स्वयं को नष्ट करने में व्यस्त है, इसके लिए कई सावधानियों की तुलना में अधिक सावधानी से कोडिंग की आवश्यकता होती है। (सीपीथॉन क्लीनअप को आमतौर __del__पर दुभाषिया बंद पर चलने के तरीके मिलते हैं, लेकिन अभी भी ऐसे मामले हैं जहां यह पर्याप्त नहीं है। डेमन थ्रेड्स, सी-लेवल ग्लोबल्स और __del__अन्य में बनाए गए ऑब्जेक्ट __del__सभी __del__चल रहे तरीकों का नेतृत्व कर सकते हैं ।)
user2357112 समर्थन करता है। मोनिका

80

मैंने एक और प्रश्न का उत्तर लिखा है, हालांकि यह इसके लिए अधिक सटीक प्रश्न है।

निर्माता और विध्वंसक कैसे काम करते हैं?

यहाँ एक छोटा सा जवाब दिया गया है।

उपयोग न करें __del__। यह C ++ या विध्वंसक के लिए निर्मित भाषा नहीं है। __del__विधि वास्तव में, अजगर 3.x में चला जाना चाहिए, हालांकि मुझे यकीन है कि किसी को एक उपयोग के मामले कि समझ में आता है मिलेगा हूँ। यदि आपको उपयोग करने की आवश्यकता है __del__, तो http://docs.python.org/reference/datamodel.html : की मूल सीमाओं से अवगत रहें :

  • __del__कहा जाता है जब कचरा संग्रहकर्ता वस्तुओं को एकत्रित करता है, तब नहीं जब आप किसी वस्तु का अंतिम संदर्भ खोते हैं और जब आप निष्पादित करते हैं तब नहीं del object
  • __del__किसी __del__सुपरक्लास में किसी भी कॉल करने के लिए जिम्मेदार है , हालांकि यह स्पष्ट नहीं है कि यह विधि रिज़ॉल्यूशन ऑर्डर (एमआरओ) में है या केवल प्रत्येक सुपरक्लास को कॉल कर रहा है।
  • एक __del__साधन होने के नाते कि कचरा कलेक्टर किसी भी चक्रीय लिंक का पता लगाने और उसकी सफाई करने के लिए छोड़ देता है, जैसे कि किसी लिंक की गई सूची का अंतिम संदर्भ खोना। आप वस्तुओं की सूची प्राप्त कर सकते हैं जिन्हें goregarbage से अनदेखा किया गया है। आप कभी-कभी चक्र से बचने के लिए कमजोर संदर्भों का उपयोग कर सकते हैं। इस पर अभी और फिर बहस होती है: http://mail.python.org/pipermail/python-ideas/2009-October/006194.html देखें ।
  • __del__समारोह धोखा कर सकते हैं, एक वस्तु के लिए एक संदर्भ की बचत, और कचरा संग्रहण रोक।
  • स्पष्ट रूप से उठाए गए अपवादों __del__को अनदेखा किया जाता है।
  • __del__से __new__कहीं अधिक का पूरक है __init__। इससे भ्रम हो जाता है। देखें http://www.algorithm.co.il/blogs/programming/python-gotchas-1- डेल -is-नहीं-विपरीत के- init / एक विवरण और gotchas के लिए।
  • __del__पायथन में एक "अच्छी तरह से प्यार करने वाला" बच्चा नहीं है। आप देखेंगे कि sys.exit () दस्तावेज़ीकरण निर्दिष्ट नहीं करता है कि बाहर निकलने से पहले कचरा एकत्र किया गया है या नहीं, और बहुत सारे विषम मुद्दे हैं। __del__ग्लोबल्स पर कॉल करने पर अजीब आदेश देने वाले मुद्दों का कारण बनता है, उदाहरण के लिए, http://bugs.python.org/issue5099 । विफल होने पर __del__भी बुलाया जाना चाहिए __init__? एक लंबे धागे के लिए http://mail.python.org/pipermail/python-dev/2000-March/thread.html#2423 देखें ।

लेकिन दूसरी ओर:

  • __del__का मतलब है कि आप एक करीबी बयान को कॉल करना न भूलें। एक समर्थक दृष्टिकोण के लिए http://eli.thegreenplace.net/2009/06/06/safely-use-destructors-in-python/ देखें __del__। यह आमतौर पर ctypes या कुछ अन्य विशेष संसाधनों को मुक्त करने के बारे में है।

और __del__फ़ंक्शन को पसंद नहीं करने के लिए मेरा पेसोनल कारण ।

  • हर कोई किसी को लाता है __del__यह भ्रम के तीस संदेशों में विकसित होता है।
  • यह पायथन के ज़ेन में इन वस्तुओं को तोड़ता है:
    • सरल जटिल से बेहतर है।
    • नियम तोड़ने के लिए विशेष मामले पर्याप्त नहीं हैं।
    • त्रुटियों को कभी भी चुपचाप नहीं गुजरना चाहिए।
    • अस्पष्टता के सामने, अनुमान लगाने के प्रलोभन से इनकार करें।
    • एक होना चाहिए - और अधिमानतः केवल एक - स्पष्ट तरीका यह करने के लिए।
    • यदि कार्यान्वयन को समझाना कठिन है, तो यह एक बुरा विचार है।

तो, उपयोग न करने का एक कारण ढूंढें __del__


6
यहां तक ​​कि अगर सवाल ठीक नहीं है: हमें क्यों नहीं उपयोग करना चाहिए __del__, लेकिन कॉल कैसे करें __del__, आपका जवाब दिलचस्प है।
नबर

धन्यवाद। कभी-कभी सबसे अच्छा विचार भयानक विचारों से दूर जाना है।
चार्ल्स मेरियम

अन्य समाचारों में, मैं यह उल्लेख करना भूल गया कि PyPy (लंबे समय तक चलने वाले ऐप्स के लिए एक तेज़ दुभाषिया) डेल पर टूट जाएगा ।
चार्ल्स मेरियम

टूटी हुई कड़ी को अपडेट करने के लिए @Gloin को धन्यवाद!
चार्ल्स मेरियम

@CharlesMerriam धन्यवाद आप जवाब के लिए!
टॉम बुरो

13

__del__विधि है, यह जब वस्तु कचरा एकत्र है बुलाया जाएगा। ध्यान दें कि यह जरूरी नहीं है कि हालांकि बुलाया जाए। निम्नलिखित कोड अपने आप जरूरी नहीं होगा:

del obj

इसका कारण यह है कि delबस संदर्भ संख्या को एक-एक करके घटाता है। यदि किसी वस्तु का संदर्भ कुछ और है, तो __del__उसे कॉल नहीं किया जाएगा।

__del__हालांकि उपयोग करने के लिए कुछ चेतावनी हैं । आम तौर पर, वे आमतौर पर बहुत उपयोगी नहीं होते हैं। यह मुझे और अधिक लगता है जैसे आप एक करीबी विधि या शायद ए का उपयोग करना चाहते हैं बयान के साथ

पर अजगर प्रलेखन देखें__del__तरीकों

नोट करने के लिए एक और बात: __del__विधियाँ कचरा संग्रह को रोक सकती हैं यदि अति प्रयोग किया जाता है। विशेष रूप से, एक परिपत्र संदर्भ जिसमें एक __del__विधि के साथ एक से अधिक ऑब्जेक्ट है, कचरा एकत्र नहीं किया जाएगा। इसका कारण यह है कि कचरा संग्रहकर्ता को यह पता नहीं होता है कि पहले किसे बुलाना है। अधिक जानकारी के लिए gc मॉड्यूल पर प्रलेखन देखें ।


8

__del__जब आपके वस्तु अंत में नष्ट हो जाता है विधि (नोट वर्तनी!) कहा जाता है। तकनीकी रूप से बोलना (cPython में) वह है जब आपकी वस्तु के लिए कोई संदर्भ नहीं होते हैं, अर्थात जब यह कार्यक्षेत्र से बाहर हो जाता है।

यदि आप अपनी वस्तु को हटाना चाहते हैं और इस प्रकार __del__विधि का उपयोग करते हैं

del obj1

जो वस्तु को हटा देगा (बशर्ते कि इसके अन्य संदर्भ नहीं थे)।

मेरा सुझाव है कि आप इस तरह से एक छोटा वर्ग लिखें

class T:
    def __del__(self):
        print "deleted"

और अजगर दुभाषिया में जांच, उदा

>>> a = T()
>>> del a
deleted
>>> a = T()
>>> b = a
>>> del b
>>> del a
deleted
>>> def fn():
...     a = T()
...     print "exiting fn"
...
>>> fn()
exiting fn
deleted
>>>   

ध्यान दें कि jython और ironpython के अलग-अलग नियम होते हैं, जब ऑब्जेक्ट हटा दिया जाता है और __del__कहा जाता है। इसका उपयोग करने के लिए अच्छा अभ्यास नहीं माना जाता है __del__क्योंकि इस तथ्य और इस तथ्य के कारण कि ऑब्जेक्ट और उसका वातावरण अज्ञात स्थिति में हो सकता है जब इसे कहा जाता है। यह बिल्कुल गारंटी नहीं है कि __del__या तो बुलाया जाएगा - दुभाषिया सभी वस्तुओं को हटाए बिना विभिन्न तरीकों से बाहर निकल सकता है।


1
के साथ तुलना में stackoverflow.com/a/2452895/611007 और stackoverflow.com/a/1481512/611007 , use del obj1लगता है एक बुरा विचार की तरह पर निर्भर रहना पड़ता।
n611x007

0

जैसा कि पहले उल्लेख किया गया है, __del__कार्यक्षमता कुछ अविश्वसनीय है। ऐसे मामलों में जहां यह उपयोगी लग सकता है, इसके बजाय __enter__और __exit__विधियों का उपयोग करने पर विचार करें । यह with open() as f: passफ़ाइलों तक पहुँचने के लिए उपयोग किए गए सिंटैक्स के समान व्यवहार देगा । __enter__के दायरे में प्रवेश करने पर स्वचालित रूप से कहा जाता है with, जबकि __exit__इसे बाहर निकलते समय स्वचालित रूप से कहा जाता है। देखें इस सवाल का अधिक जानकारी के लिए।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.