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

如何在Python中实现支持弱引用/垃圾回收的对象驻留?

实现支持弱引用/垃圾回收的非字符串对象驻留

问题背景

需要为非字符串的不可变对象实现驻留(即相同内容的对象返回同一实例),替代仅支持字符串的sys.intern,但普通字典的强引用会导致内存无限增长;WeakSet虽支持自动回收,但查找效率极低;WeakKey/ValueDictionary也无法直接满足“弱引用+快速查找”的需求。

可行解决方案

方案1:哈希分组+WeakSet优化查找

核心思路是用哈希值对对象分组,将同一哈希的对象存入对应WeakSet,查找时仅遍历相同哈希的候选对象,大幅提升效率,同时WeakSet会自动回收无强引用的对象。

import weakref

class WeakInterner:
    def __init__(self):
        # 键:对象哈希值,值:存储对应哈希对象的WeakSet
        self._hash_groups = {}

    def intern(self, obj):
        obj_hash = hash(obj)
        # 获取当前哈希对应的WeakSet,不存在则创建
        group = self._hash_groups.setdefault(obj_hash, weakref.WeakSet())
        # 在分组内查找相等的对象
        for existing in group:
            if existing == obj:
                return existing
        # 无匹配对象,加入分组并返回原对象
        group.add(obj)
        return obj

使用示例

# 定义一个自定义不可变类(需实现__eq__和__hash__)
class ImmutableItem:
    def __init__(self, id, value):
        self._id = id
        self._value = value

    def __eq__(self, other):
        if not isinstance(other, ImmutableItem):
            return False
        return self._id == other._id and self._value == other._value

    def __hash__(self):
        return hash((self._id, self._value))

# 初始化驻留器
interner = WeakInterner()

# 创建两个内容相同的对象
item1 = ImmutableItem(1, "test")
item2 = ImmutableItem(1, "test")

# 驻留后指向同一实例
interned1 = interner.intern(item1)
interned2 = interner.intern(item2)
print(interned1 is interned2)  # 输出: True

# 移除所有强引用,触发GC后对象会被回收
del item1, item2, interned1, interned2
import gc
gc.collect()

# 对应哈希分组已为空
print(len(interner._hash_groups[hash(ImmutableItem(1, "test"))]))  # 输出: 0

关键注意事项

  • 对象必须不可变:驻留对象若被修改,所有引用该实例的代码都会受到影响,这是驻留的固有风险,需自行把控。
  • 实现正确的__eq__和__hash__:自定义类必须手动实现这两个方法,确保哈希值与对象内容关联,且相等的对象哈希值一致。
  • GC回收时机:WeakSet中的元素会在对象无强引用时自动移除,但GC不会立即触发,需等待自动GC或手动调用gc.collect()。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 13:13:13