为什么weakref不能用这种绑定方法?

2024-10-01 15:29:25 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个项目,我试图使用weakrefs和回调,但我不明白我做错了什么。我创建了一个简化的测试,它显示了我所困惑的确切行为。在

为什么在这个测试中测试_a和预期一样工作,但是weakrefself.mycallback在类初始化和调用测试之间消失?我想只要实例(a)存在,引用self.mycallback应该存在,但事实并非如此

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()

Tags: 项目testselfdefproxyprint消失weakref
3条回答

根据Weakref模块的文档:

In the following, the term referent means the object which is referred to by a weak reference.

A weak reference to an object is not enough to keep the object alive: when the only remaining references to a referent are weak references, garbage collection is free to destroy the referent and reuse its memory for something else.

MyCallbackA的实际情况是,在a的实例中,您持有对它的引用,这要归功于-

self.MyCallbackA = MyCallbackA

现在,代码中没有对绑定方法mycallback的引用。它只作为一个未绑定的方法保存在一个。基本上,当您创建绑定方法时(并返回给您)self.methodName. (AFAIK,绑定方法的工作方式类似于属性-使用描述符(只读):至少对于新样式类。我敢肯定,在老式类中也会发生类似的不带描述符的情况。我会让更有经验的人来验证关于旧样式类的说法。)所以,self.mycallback一旦weakref被创造出来就死了,因为没有强有力的参考!在

我的结论基于:

^{pr2}$

输出

Create MyCallbackB
Del MycallbackB
Done playing with MyCallbackB
MyCallbackA

注意:
我试着在旧式课程中验证这一点。结果是“打印一份测试报告” 输出-

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

对于新的和旧的样式类。所以它可能不是真正的描述符,只是类似于描述符的东西。在任何情况下,关键是通过self访问实例方法时会创建绑定方法对象,除非维护对它的强引用,否则它将被删除。在

你想要一个WeakMethod。在

你的解决方案不起作用的解释可以在配方讨论中找到:

Normal weakref.refs to bound methods don't quite work the way one expects, because bound methods are first-class objects; weakrefs to bound methods are dead-on-arrival unless some other strong reference to the same bound method exists.

其他答案解决了原始问题中的为什么,但要么不提供解决方法,要么引用外部站点。在

在阅读了StackExchange上关于这个主题的其他几篇文章之后,我终于找到了一个简洁的解决方法。当我知道我正在处理的对象的性质时,我使用weakref模块;当我可能正在处理一个绑定方法(就像在我的代码中使用事件回调时发生的那样),我现在使用下面的weakref类作为weakref参考(). 我已经用python2.4到python2.7进行了测试,但没有在python3.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__)

相关问题 更多 >

    热门问题