2016-05-14 6 views
16

मैं वर्तमान में उपयोग में आने वाले किसी निश्चित प्रकार की वस्तुओं का ट्रैक रखना चाहता हूं। उदाहरण के लिए: किसी वर्ग या सभी वर्गों के मेटाक्लास द्वारा बनाए गए सभी उदाहरणों का ट्रैक रखें।पायथन में: किसी ऑब्जेक्ट को किसी सूची से कैसे निकालें यदि इसे केवल उस सूची में संदर्भित किया गया हो?

यह इस तरह उदाहरणों का ट्रैक रखने के लिए आसान है:

class A(): 
    instances = [] 
    def __init__(self): 
     self.instances.append(self) 

लेकिन अगर एक उदाहरण है कि सूची में यह अब कोई आवश्यकता नहीं किया जाएगा के बाहर कहीं भी संदर्भित नहीं है और मैं में है कि उदाहरण के कार्रवाई करने के लिए नहीं करना चाहते हैं एक संभावित समय लेने वाला पाश।

मैंने उन वस्तुओं को निकालने का प्रयास किया जो केवल sys.getrefcount का उपयोग करके सूची में संदर्भित हैं।

for i in A.instances: 
    if sys.getrefcount(i) <=3: # in the list, in the loop and in getrefcount 
     # collect and remove after the loop 

मेरी समस्या यह है कि संदर्भ गणना बहुत अस्पष्ट है। एक नया खोल खुलने और के लिए

sys.getrefcount(DummyClass) 

एक और विचार वस्तुओं तो कॉपी करने के लिए सूची और जाँच जो वस्तुओं कचरा एकत्र करने के लिए और हटाने अंतिम चरण में निर्धारित किये गये हटाने से कोई सामग्री रिटर्न 5 के साथ एक डमी वर्ग बनाने उन वस्तुओं। कुछ की तरह:

Copy = copy(A.instances) 
del A.instances 
A.instances = [i for i in Copy if not copy_of_i_is_in_GC(i)] 

वस्तुओं तुरंत हटा दिया जाना चाहिए जब संदर्भ गिनती 0. को जाता है मैं सिर्फ वस्तुओं है कि अब और उपयोग नहीं किया जाता पर बहुत अधिक ressources बर्बाद करने के लिए नहीं करना चाहती नहीं है।

+1

एक [कमजोर संदर्भ] (https://docs.python.org/3.5/library/weakref.html) – Barmar

+0

http://stackoverflow.com/questions/12101958/keep-track-of-instances-in का उपयोग करें -पीथन –

+0

http://effbot.org/pyfaq/how-do-i-get-a-list-of-all-instances-of-a-given-class.htm –

उत्तर

7

यह उत्तर केविन के समान है लेकिन मैं कमजोर संदर्भों के साथ एक उदाहरण कार्यान्वयन का काम कर रहा था और इसे यहां पोस्ट कर रहा हूं। कमजोर संदर्भों का उपयोग करने से समस्या हल होती है जहां किसी ऑब्जेक्ट को self.instance सूची द्वारा संदर्भित किया जाता है, इसलिए इसे कभी भी हटाया नहीं जाएगा।

किसी ऑब्जेक्ट के लिए कमजोर संदर्भ बनाने के बारे में चीजों में से एक यह है कि ऑब्जेक्ट हटा दिए जाने पर आप कॉलबैक शामिल कर सकते हैं। कार्यक्रम समाप्त होने पर कॉलबैक जैसे समस्याएं नहीं हो रही हैं ... लेकिन यह वही हो सकता है जो आप चाहते हैं।

import threading 
import weakref 

class A(object): 
    instances = [] 
    lock = threading.RLock() 

    @classmethod 
    def _cleanup_ref(cls, ref): 
     print('cleanup') # debug 
     with cls.lock: 
      try: 
       cls.instances.remove(ref) 
      except ValueError: 
       pass 

    def __init__(self): 
     with self.lock: 
      self.instances.append(weakref.ref(self, self._cleanup_ref)) 

# test 
test = [A() for _ in range(3)] 
for i in range(3,-1,-1): 
    assert len(A.instances) == i 
    if test: 
     test.pop() 

print("see if 3 are removed at exit") 
test = [A() for _ in range(3)] 
+0

पायथन शेल (3.5.1) में टेस्ट लूप में दावा विफल रहता है क्योंकि लूप जब दूसरी बार दावे तक पहुंच जाता है तो क्लीनअप कॉलबैक नहीं कहा जाता है। जोरदार बयान से पहले या test.pop() के बाद stdout करने के लिए कुछ भी प्रिंटिंग। इसलिए, "जोर" से पहले "झूठा" रखना इसे ठीक करता है, जबकि "कोई नहीं" इसे ठीक नहीं करता है। – uzumaki

+0

@uzumaki दिलचस्प। मैंने पायथन 3.4 के साथ परीक्षण किया। मुझे परेशान है कि 3.5 में कॉलबैक क्यों नहीं हुआ है। – tdelaney

6

इस समस्या को हल करने के लिए मानक तरीका weak references माध्यम से है। मूल विचार यह है कि आप वस्तुओं की बजाय वस्तुओं के कमजोर संदर्भों की एक सूची रखते हैं, और समय-समय पर सूची से मृत कमजोर संदर्भों को छीनते हैं।

शब्दकोश और सेट के लिए, कुछ और अमूर्त प्रकार जैसे weakref.WeakKeyDictionary() हैं जिनका उपयोग तब किया जा सकता है जब आप एक शब्दकोश की कुंजी जैसे अधिक जटिल स्थानों में कमजोर संदर्भ डालना चाहते हैं। इन प्रकारों को मैन्युअल छंटनी की आवश्यकता नहीं है।

1

उनका कहना है weakref का उपयोग करने के लिए @Barmar के लिए धन्यवाद। हम कक्षा के स्वयं प्रबंधन उदाहरण सूची को लागू करने के लिए __del__ विधि के साथ इसे जोड़ सकते हैं।हालांकि ऐसा नहीं है,

from weakref import ref 
class A(): 
    instances = [] 
    def __init__(self): 
     self.instances.append(ref(self)) 

    @staticmethod 
    def __del__(): 
     if A: 
     A.instances = [i for i in A.instances if not i() is None] 

परीक्षण

#python2.7 
print dict((len(A.instances), A()) for i in range(5)).keys() # 0,1,2,3,4 
print len(A.instances) # 0 

नाशक __del__ एक स्थिर विधि या def __del__(self): की तरह एक वस्तु बाध्य विधि के रूप में घोषित किया जा सकता: इस प्रकार, ओपी की पोस्ट में class A के रूप में बढ़ाया जा सकता है दस्तावेज। उत्तरार्द्ध वस्तु को इसके संदर्भ में एक और संदर्भ बनाकर नष्ट कर सकता है। यहां मैं स्थैतिक का उपयोग करता हूं क्योंकि मरने वाली वस्तु के दूसरे संदर्भ की आवश्यकता नहीं है। उपरोक्त कोड पायथन 2.7 और 3.3 दोनों में परीक्षण किया जाता है।

weakref.ref कॉलबैक __del__ के समान व्यवहार करता है सिवाय इसके कि यह "कमजोर" ऑब्जेक्ट से जुड़ा हुआ है। इसलिए यदि आप एक ही ऑब्जेक्ट के लिए एक ही कॉलबैक फ़ंक्शन के साथ एकाधिक कमजोर बनाते हैं, तो इसे कमजोरियों की संख्या के बराबर सटीक कहा जाएगा।

+0

ध्यान दें कि ['__del__'] (https://docs.python.org/3.5/reference/datamodel.html#object.__del__) एक स्थैतिक विधि नहीं होनी चाहिए। साथ ही 'i() कोई नहीं है 'बेहतर लिखा गया है' i() कोई नहीं है '। साथ ही, जैसा कि tdelaney दिखाता है 'weakref.ref' पहले से ही कॉलबैक जोड़ने का माध्यम प्रदान करता है जिसे ऑब्जेक्ट नष्ट हो जाता है। – Bakuriu

+0

@ बाकुरी: टिप्पणी के लिए धन्यवाद, कृपया '__del__' और' weakref.ref' के बारे में चर्चा के लिए अद्यतन उत्तर देखें – gdlmx

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