لماذا لا يعمل الضعيف في هذه الطريقة المحتملة؟

StackOverflow https://stackoverflow.com/questions/599430

  •  11-09-2019
  •  | 
  •  

سؤال

لدي مشروع أحاول فيه استخدام الضعف مع ردود الاستدعاء، وأنا لا أفهم ما أفعله خطأ. لقد قمت بإنشاء اختبار مبسط يظهر السلوك الدقيق الذي أقيم فيه.

لماذا هو أنه في هذا الاختبار Test_a يعمل كما هو متوقع، ولكن يختفي الضعف ل Self.mycallbackb بين تهيئة الفصل والاتصال Test_b؟ فكرت كما طالما أن المثيل (أ) موجود، يجب أن يكون الإشارة إلى Self.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()
هل كانت مفيدة؟

المحلول

كنت ترغب في ضعيفة.

يمكن العثور على شرح لماذا لا يعمل الحل الخاص بك في مناقشة الوصفة:

Normal Lyvref.Refs إلى الطرق الملزمة لا تعمل تماما بالطريقة التي يتوقعها المرء، لأن الطرق المحددة هي كائنات من الدرجة الأولى؛ الضعيف في الأساليب المنتصلة ميت عند الوصول ما لم يكن هناك بعض المرجع القوي الأخرى إلى نفس الطريقة المحددة.

نصائح أخرى

وفقا للوثائق لنمط الضعيف:

في ما يلي، يعني مصطلح المرجع أن الكائن الذي يشار إليه بموجب مرجع ضعيف.

إشارة ضعيفة إلى كائن لا يكفي للحفاظ على الكائن حيا: عندما تكون المراجع المتبقية الوحيدة إلى مراجع ضعيفة، فإن جمع القمامة مجاني لتدمير ذاكرته وإعادة استخدام ذاكرتها لشيء آخر.

ما يحدث مع MyCallbacka هو أنك تحمل مرجعا إليه في حالات A، بفضل -

self.MyCallbackA = MyCallbackA

الآن، لا يوجد إشارة إلى الطريقة المنضم mycallbackb في التعليمات البرمجية الخاصة بك. إنه محتجز فقط في فئة __.__ dict__ كطريقة غير منوعة. في الأساس، يتم إنشاء طريقة ملزمة (وعادتها إليك) عند القيام Self.methetname. (AFAIK، وهي طريقة ملزمة تعمل مثل الممتلكات - أي وصف واصف (للقراءة فقط): على الأقل بالنسبة لفصول أسلوب جديد. أنا متأكد من أن أي شيء مماثل مع واصفات W / O يحدث في فصول النمط القديم. سأترك الأمر شخص ما أكثر خبرة للتحقق من المطالبة حول فصول النمط القديم.) لذلك، وفاة Self.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.

ملحوظة :
حاولت التحقق من فصول النمط القديم. اتضح أن "طباعة A.Test_a .__ الحصول على مخرجات" -

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

لكل من فصول النمط الجديد والكبار. لذلك قد لا يكون حقا واصف، فقط شيء واصف مثل. في أي حال، فإن النقطة هي أن كائن طريقة ملزمة يتم إنشاؤه عند تأسيس طريقة مثيل من خلال الذات، وما لم تحافظ على مرجع قوي عليه، سيتم حذفه.

الإجابات الأخرى تعالج لماذا في السؤال الأصلي، ولكن إما لا توفر الحل أو الرجوع إلى المواقع الخارجية.

بعد العمل من خلال العديد من الوظائف الأخرى حول StackExchange حول هذا الموضوع، يتم تمييز العديد منها على أنها مكررة لهذا السؤال، وأخيرا جاءت إلى حل مميز. عندما أعرف طبيعة الكائن، أتعامل مع الوحدة الضعيفة؛ عندما أكون بدلا من ذلك، أن أتعامل مع طريقة ملزمة (كما يحدث في التعليمات البرمجية عند استخدام ردود الاحتياطات)، فأنا الآن استخدم فئة ضعف الضعف كاستبدال مباشر للإضعاف (). لقد اختبرت هذا مع بيثون 2.4 من خلال و بما في ذلك بيثون 2.7، ولكن ليس على Python 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__)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top