我可以弱引用方法吗?

5 投票
2 回答
1925 浏览
提问于 2025-04-16 23:05

可能重复的问题:
为什么弱引用在这个绑定方法上不起作用?

背景介绍:

我在尝试实现一个监听器(或观察者,意思一样)模式:一个事件管理器会保持一个感兴趣事件的所有监听器处理程序的列表。例如,一个监听器对象会有一个 onEndOfTheWorldEvent 方法,每当有一个名为 EndOfTheWorldEvent 的事件实例被发布时,事件管理器就会调用这个方法。听起来很简单。

但我想用弱引用来引用这些处理程序,因为我不想让事件管理器在监听器不再需要时仍然保持这些处理程序(绑定方法)活着。

所以我想,“那就把所有处理程序放到一个弱集合(WeakSet)里。”但我没能让它工作。

我把代码(或者说我把它简化到最小后剩下的部分,这里只有一种事件和一种处理程序)放在这里。

#! /usr/bin/python
"""

"""
import sys
import weakref

class Listener(object):
    def handler(self, event):
        print event

class EventManager(object):
    def __init__(self):
        self.handlers = weakref.WeakSet()
    def register(self, listener):
        print "Registering..."
        self.handlers.add(listener.handler)
        CountRefs(listener.handler)
        print "Number of handlers registered:", len(self.handlers)
        print "Registered."

def CountRefs(what):
    print "Hard count:", sys.getrefcount(what)
    print "Weak count:", weakref.getweakrefcount(what)

listener = Listener()
em = EventManager()
CountRefs(listener.handler)
em.register(listener)
CountRefs(listener.handler)

结果:

Hard count: 3
Weak count: 0
Registering...
Hard count: 3
Weak count: 0
Number of handlers registered: 0
Registered.
Hard count: 3
Weak count: 0

看起来似乎从来没有任何弱引用,集合始终是空的。

为了更简单明了:

>>> class C(object):
>>>     def blah(self):
>>>         print "blah"
>>> 
>>> c = C()
>>> w = weakref.ref(c.blah)
>>> print w
<weakref at 0x11e59f0; dead>

我根本不能为方法创建弱引用吗?如果不能,为什么呢

所以我想一个解决办法是用一个弱键字典(WeakKeyDictionary)来替代弱集合:键是监听器本身,值是处理程序。确实,我可以对我的监听器使用弱引用。但这让数据结构变得有点复杂,当需要将事件广播给所有人时,还要多一层结构需要处理。

你怎么看?

2 个回答

2

listener.handler 每次都会给你一个新的函数引用。所以这个引用几乎会立刻被系统回收掉。

8

假设你想在一个叫“meth”的方法上使用弱引用。

你可以这样获取它的弱引用:

weak_obj = weakref.ref(meth.im_self)
weak_func = weakref.ref(meth.im_func)

这样,你就可以像这样解除引用:

obj = weak_obj()
func = weak_func()

然后用下面的方式重新得到“meth”:

meth = getattr(obj, func.__name__)

撰写回答