2017-01-25 10 views
7

मैं an example in David Beazley's Python Essential Reference पढ़ें:__del __() कचरा संग्रह में हस्तक्षेप कैसे करता है?

class Account(object): 
    def __init__(self,name,balance): 
     self.name = name 
     self.balance = balance 
     self.observers = set() 
    def __del__(self): 
     for ob in self.observers: 
      ob.close() 
     del self.observers 
    def register(self,observer): 
     self.observers.add(observer) 
    def unregister(self,observer): 
     self.observers.remove(observer) 
    def notify(self): 
     for ob in self.observers: 
      ob.update() 
    def withdraw(self,amt): 
     self.balance -= amt 
     self.notify() 

class AccountObserver(object): 
    def __init__(self, theaccount): 
     self.theaccount = theaccount 
     theaccount.register(self) 
    def __del__(self): 
     self.theaccount.unregister(self) 
     del self.theaccount 
    def update(self): 
     print("Balance is %0.2f" % self.theaccount.balance) 
    def close(self): 
     print("Account no longer in use") 

# Example setup 
a = Account('Dave',1000.00) 
a_ob = AccountObserver(a) 

यह उल्लेख किया गया है कि

... कक्षाएं एक संदर्भ चक्र जिसमें संदर्भ गिनती 0 के लिए कभी नहीं चला जाता है और वहाँ कोई सफाई है बनाया है। इतना ही नहीं, कचरा कलेक्टर (gc मॉड्यूल) इसे साफ़ भी नहीं करेगा, जिसके परिणामस्वरूप स्थायी स्मृति रिसाव हो जाएगा।

क्या कोई यह समझा सकता है कि यह कैसे होता है? कमजोरियों कैसे मदद कर सकते हैं?

उत्तर

7

Account().observersAccountObserver() उदाहरणों को संदर्भित एक सेट है, लेकिन AccountObserver().theaccount एक संदर्भ वापसAccount() उदाहरण जहां पर्यवेक्षक सेट में संग्रहीत किया जाता है की ओर इशारा करते है। यह एक परिपत्र संदर्भ है।

आम तौर पर, कचरा कलेक्टर ऐसी मंडलियों का पता लगाएगा और चक्र तोड़ देगा, जिससे संदर्भ संख्या 0 तक गिर जाएगी और सामान्य सफाई हो जाएगी। हालांकि, एक अपवाद है, जो कक्षाओं के लिए __del__ विधि को परिभाषित करता है, क्योंकि डेविड के उदाहरण में कक्षाएं होती हैं। Python 2 gc module documenation से:

gc.garbage
वस्तुओं जो कलेक्टर नहीं पहुंचा जा सकता हो पाया लेकिन मुक्त नहीं किया जा सकता है (uncollectable वस्तुओं) की सूची। डिफ़ॉल्ट रूप से, इस सूची में केवल __del__() विधियों वाली वस्तुएं होती हैं। ऑब्जेक्ट्स जिनमें __del__() विधियां हैं और संदर्भ चक्र का हिस्सा हैं, पूरे संदर्भ चक्र को अस्थिर करने योग्य, जिसमें ऑब्जेक्ट्स शामिल नहीं हैं, केवल चक्र में आवश्यक है लेकिन केवल इससे ही पहुंच योग्य है। पाइथन स्वचालित रूप से ऐसे चक्र एकत्र नहीं करता है, सामान्य रूप से, पाइथन के लिए सुरक्षित आदेश अनुमान लगाना संभव नहीं है जिसमें __del__() विधियों को चलाने के लिए।

तो चक्र क्योंकि कचरा कलेक्टर अनुमान लगाना क्या finaliser (__del__ विधि) पहले कॉल करने के लिए मना कर दिया तोड़ा नहीं जा सकता है। ध्यान दें कि यादृच्छिक रूप से एक को चुनना विशिष्ट उदाहरण के लिए सुरक्षित नहीं है; यदि आप पहले Account().__del__ पर कॉल करते हैं, तो observers सेट हटा दिया गया है और AccountObserver().__del__ पर आने वाली कॉल AttributeError के साथ विफल हो जाएंगी।

एक कमजोर संदर्भ संदर्भ गणना में भाग नहीं लेता है; इसलिए यदि AccountObserver().theaccount इसी Account() बजाय उदाहरण के लिए बात करने के लिए एक कमजोर संदर्भ में प्रयोग किया जाता है, तो Account() उदाहरण नहीं जिंदा रखा जाएगा अगर केवल कमजोर संदर्भ छोड़ दिया गया:

class AccountObserver(object): 
    def __init__(self, theaccount): 
     self.theaccountref = weakref.ref(theaccount) 
     theaccount.register(self) 

    def __del__(self): 
     theaccount = self.theaccountref() 
     if theaccount is not None:  
      theaccount.unregister(self) 

    def update(self): 
     theaccount = self.theaccountref() 
     print("Balance is %0.2f" % theaccount.balance) 

    def close(self): 
     print("Account no longer in use") 

ध्यान दें कि मैं अजगर 2 प्रलेखन से लिंक। अजगर 3.4 के रूप में, यह नहीं रह गया है सच और उदाहरण में शो के रूप में भी परिपत्र निर्भरता साफ हो जाएगा, के रूप में PEP 442 – Safe object finalization लागू किया गया है:

प्राथमिक जैसे इस पीईपी संबंध finalizers साथ वस्तुओं के लाभ, अंततः ब्लॉक के साथ __del__ विधि और जनरेटर वाले ऑब्जेक्ट्स। जब वे संदर्भ चक्र का हिस्सा होते हैं तो उन वस्तुओं को पुनः दावा किया जा सकता है।

ऐसा नहीं है कि इससे ट्रेसबैक नहीं होगा; ट्रैस बैक सिर्फ एक चेतावनी अन्यथा है

>>> import gc 
>>> del a, a_ob 
>>> gc.collect() 
Account no longer in use 
Exception ignored in: <bound method AccountObserver.__del__ of <__main__.AccountObserver object at 0x10e36a898>> 
Traceback (most recent call last): 
    File "<stdin>", line 6, in __del__ 
    File "<stdin>", line 13, in unregister 
AttributeError: 'Account' object has no attribute 'observers' 
65 

: यदि आप अजगर 3.6 में उदाहरण पर अमल, संदर्भ हटा देते हैं और शुरू एक कचरा संग्रहण रन, आप के रूप में Account().observers सेट हटा दिया गया है की संभावना है ट्रैसबैक मिल , gc.collect() कॉल सफल हुआ और ज़ोंबी AccountObserver() और Account() ऑब्जेक्ट्स का वैसे भी उपयोग किया जाता है।

+0

उत्तर के लिए धन्यवाद, मार्टिजन। मेरे पास एक प्रश्न है- '__init __() 'के अंदर संशोधित' खाता ऑब्सर्वर 'कक्षा में, क्या यह गलत होगा अगर मैंने' रजिस्टर() 'को कमजोर के रूप में' theaccountref.register (self) 'के रूप में मूल' अकाउंट' रजिस्ट्रार (स्वयं) '? '__del __()' –

+0

@Sajeev राजपूत के लिए भी जाता है: आपको 'theaccountref() रजिस्टर (स्वयं)' का उपयोग करना होगा, इसलिए * ऑब्जेक्ट * मूल ऑब्जेक्ट प्राप्त करने के संदर्भ में। लेकिन आपके पास पहले से ही उस ऑब्जेक्ट का संदर्भ है, स्थानीय चर 'अकाउंट' के रूप में, तो इसका उपयोग क्यों न करें? जब '__init__' समाप्त होता है, तो उस संदर्भ को हटाकर' theaccount' स्थानीय चर साफ़ कर दिया जाता है। –

+0

@ सजीव राजपूत: '__del__' में आपके पास 'खाता()' उदाहरण के लिए कोई अन्य संदर्भ नहीं है; यह एक कमजोर संदर्भ का उपयोग करने का पूरा बिंदु है। तो आपको कमजोर वस्तु को कॉल करना होगा, और यदि 'कोई नहीं' वापस लौटाया गया था तो मूल वस्तु अब और नहीं है। –

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