2009-03-01 15 views
9

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

ऐसा क्यों है कि इस परीक्षण में test_a अपेक्षित काम करता है, लेकिन स्वयं के लिए कमजोर है। MyCallbackB क्लास प्रारंभिकरण और test_b को कॉल करने के बीच गायब हो जाता है? मैंने सोचा कि जब तक आवृत्ति (ए) मौजूद है, स्वयं का संदर्भ। MyCallbackB मौजूद होना चाहिए, लेकिन ऐसा नहीं है।

import weakref 

class A(object): 
    def __init__(self): 

     def MyCallbackA(): 
      print 'MyCallbackA' 
     self.MyCallbackA = MyCallbackA 

     self._testA = weakref.proxy(self.MyCallbackA) 
     self._testB = weakref.proxy(self.MyCallbackB) 

    def MyCallbackB(self): 
     print 'MyCallbackB' 

    def test_a(self): 
     self._testA() 

    def test_b(self): 
     self._testB() 

if __name__ == '__main__': 
    a = A()  
    a.test_a() 
    a.test_b() 

उत्तर

10

आप WeakMethod चाहते हैं।

एक व्याख्या क्यों अपने समाधान काम नहीं करता है नुस्खा की चर्चा में पाया जा सकता है: बाध्य तरीकों काफी रास्ता एक उम्मीद से काम नहीं करते के लिए

सामान्य weakref.refs, क्योंकि बाध्य तरीके हैं प्रथम श्रेणी की वस्तुओं; बाध्य तरीकों के लिए कमजोर पड़ने वाले मृत-आगमन-आगमन हैं जब तक कि एक ही बाध्य विधि के कुछ अन्य मजबूत संदर्भ मौजूद नहीं हैं।

4

Weakref मॉड्यूल के लिए प्रलेखन के अनुसार:

निम्नलिखित में, शब्द दिग्दर्शन वस्तु जो एक कमजोर संदर्भ द्वारा में जाना जाता है का मतलब है। , जब एक दिग्दर्शन करने के लिए ही शेष संदर्भ कमजोर संदर्भ हैं कचरा संग्रह दिग्दर्शन को नष्ट करने और के लिए अपने स्मृति पुन: उपयोग के लिए स्वतंत्र है:

एक वस्तु को एक कमजोर संदर्भ वस्तु जीवित रखने के लिए पर्याप्त नहीं है कुछ और।

self.MyCallbackA = MyCallbackA 

अब, अपने कोड में बाध्य विधि MyCallbackB लिए कोई सन्दर्भ नहीं है -

क्या MyCallbackA साथ हो रहा है कि आप एक के मामलों में यह करने के लिए एक संदर्भ के पकड़े हुए हैं, धन्यवाद करने के लिए है। यह केवल एक .__ वर्ग __.__ dict__ में एक अनबाउंड विधि के रूप में आयोजित किया जाता है। असल में, जब आप self.methodName करते हैं तो एक बाध्य विधि बनाई जाती है (और आपके पास वापस आती है)। (AFAIK, एक बाध्य विधि एक संपत्ति की तरह काम करती है - एक वर्णनकर्ता (केवल पढ़ने के लिए) का उपयोग करना: कम से कम नए स्टाइल कक्षाओं के लिए। मुझे यकीन है कि कुछ समान अर्थात् पुराने/ओएस वर्णक पुराने शैली वर्गों के लिए होता है। मैं इसे छोड़ दूंगा किसी और को पुरानी स्टाइल कक्षाओं के बारे में दावा सत्यापित करने के लिए अधिक अनुभवी।) तो, स्वयं। MyCallbackB जैसे ही कमजोर पड़ता है, मर जाता है, क्योंकि इसमें कोई मजबूत संदर्भ नहीं है!

मेरे निष्कर्ष पर आधारित होते हैं: -

import weakref 

#Trace is called when the object is deleted! - see weakref docs. 
def trace(x): 
    print "Del MycallbackB" 

class A(object): 
    def __init__(self): 

     def MyCallbackA(): 
      print 'MyCallbackA' 
     self.MyCallbackA = MyCallbackA 
     self._testA = weakref.proxy(self.MyCallbackA) 
     print "Create MyCallbackB" 
     # To fix it, do - 
     # self.MyCallbackB = self.MyCallBackB 
     # The name on the LHS could be anything, even foo! 
     self._testB = weakref.proxy(self.MyCallbackB, trace) 
     print "Done playing with MyCallbackB" 

    def MyCallbackB(self): 
     print 'MyCallbackB' 

    def test_a(self): 
     self._testA() 

    def test_b(self): 
     self._testB() 

if __name__ == '__main__': 
    a = A() 
    #print a.__class__.__dict__["MyCallbackB"] 
    a.test_a() 

आउटपुट

बनाएं MyCallbackB
डेल MycallbackB
MyCallbackB
MyCallbackA

0 के साथ खेल हो गया

नोट:
मैंने पुरानी स्टाइल कक्षाओं के लिए इसे सत्यापित करने का प्रयास किया।

<method-wrapper '__get__' of instancemethod object at 0xb7d7ffcc>

दोनों नए और पुराने शैली कक्षाओं के लिए

- ऐसा नहीं है कि "प्रिंट a.test_a .__ get__" आउटपुट निकला। तो यह वास्तव में एक वर्णनकर्ता नहीं हो सकता है, बस कुछ वर्णनकर्ता की तरह। किसी भी मामले में, बिंदु यह है कि जब आप स्वयं के माध्यम से एक उदाहरण विधि acces करते हैं, और जब तक आप इसके लिए एक मजबूत संदर्भ बनाए रखते हैं, तो इसे हटा दिया जाएगा।

3

अन्य उत्तरों को मूल प्रश्न में क्यों संबोधित करते हैं, लेकिन या तो एक समाधान प्रदान नहीं करते हैं या बाहरी साइटों को संदर्भित नहीं करते हैं।

इस विषय पर स्टैक एक्सचेंज पर कई अन्य पोस्टों के माध्यम से काम करने के बाद, जिनमें से कई को इस प्रश्न के डुप्लिकेट के रूप में चिह्नित किया गया है, मैं अंत में एक संक्षिप्त कार्यवाही में आया। जब मैं उस ऑब्जेक्ट की प्रकृति को जानता हूं जिसके साथ मैं काम कर रहा हूं, तो मैं कमजोर मॉड्यूल का उपयोग करता हूं; जब मैं इसके बजाय एक बाध्य विधि से निपट रहा हूं (जैसा कि ईवेंट कॉलबैक का उपयोग करते समय मेरे कोड में होता है), अब मैं कमजोरref.ref() के लिए प्रत्यक्ष प्रतिस्थापन के रूप में निम्न WeakRef क्लास का उपयोग करता हूं। मैंने इसे पायथन 2.4 के माध्यम से और पायथन 2.7 सहित परीक्षण किया है, लेकिन पायथन 3.x पर नहीं।

class WeakRef: 

    def __init__ (self, item): 

     try: 
      self.method = weakref.ref (item.im_func) 
      self.instance = weakref.ref (item.im_self) 

     except AttributeError: 
      self.reference = weakref.ref (item) 

     else: 
      self.reference = None 


    def __call__ (self): 

     if self.reference != None: 
      return self.reference() 

     instance = self.instance() 

     if instance == None: 
      return None 

     method = self.method() 

     return getattr (instance, method.__name__) 
+1

अजगर 3 '' आइटम .__ self__' – lou

+0

आवश्यकता हो सकती है '' डीईएफ़ __eq __ (स्वयं, अन्य) के साथ 'साथ आइटम .__ func__' item.im_func' की जगह के लिए और' item.im_self': अन्य वापसी() == स्वयं() ''? क्या यह सबसे अच्छा तुलना पैटर्न है? (और शायद '' __ne__'' उलटा के रूप में) – Rafe