You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中ref与WeakMethod比较结果异常问题求助

问题:WeakMethod与ref实例在集合中被判定为相等的原因?

我使用set存储可调用对象的弱引用,这些对象包括函数、实现__call__方法的可调用实例以及绑定方法。根据Python官方文档,我对绑定方法使用weakref.WeakMethod,对其他可调用对象使用weakref.ref,但遇到了如下问题:

示例代码:

from weakref import ref, WeakMethod

class Callbacks:
    def method(self, *args, **kwargs):
        print('method()')

    def __call__(self, *args, **kwargs):
        print('__call__()')


cb = Callbacks()
listeners = set()

listeners.add(ref(cb))
print(f'#listeners: expected = 1, actual = {len(listeners)}')

listeners.add(WeakMethod(cb.method))
print(f'#listeners: expected = 2, actual = {len(listeners)}')

运行结果:

#listeners: expected = 1, actual = 1 
#listeners: expected = 2, actual = 1

经排查发现,WeakMethod(cb.method)与ref(cb)相等,尽管cb.method != cb,请问这是什么原因?


原因分析

这是因为WeakMethod的相等性判断逻辑是基于它引用的绑定方法所属的实例对象,而非绑定方法本身。

具体细节:

  • 创建WeakMethod(cb.method)时,它内部实际维护了对cb实例和method函数的引用,但在做相等性比较时,会优先对比引用的实例对象。
  • ref(cb)直接引用的就是cb实例。
  • WeakMethod的__eq__方法实现中,会和其他weakref类型(比如ref实例)比较最终指向的对象是否一致。只要两个弱引用的目标是同一个实例,就会被判定为相等。

你可以通过下面的代码验证这个结论:

r = ref(cb)
wm = WeakMethod(cb.method)
print(r() is wm())  # 输出True,因为wm()返回的是cb实例本身

因此当你把这两个对象加入set时,set会认为它们是同一个元素,第二个add操作不会增加集合的长度。

如果需要让它们在set中被视为不同元素,你可以自定义一个包装类,重新实现__eq__和__hash__方法,区分开是实例本身的弱引用还是绑定方法的弱引用。


内容的提问来源于stack exchange,提问作者bavaza

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 18:31:44