验证weakref.ref创建的弱引用不会增加对象引用计数,del原对象后引用立刻失效、绑定的回调自动触发,以及WeakValueDictionary怎么自动清理失效的key。
普通的变量赋值都会增加引用计数,weakref.ref不会。
代码import weakref class Widget: def __init__(self, name): self.name = name w = Widget("battery") r = weakref.ref(w) print(r()) # 弱引用对象本身 del w print(r()) # 原对象被删除后,弱引用还能用吗
这跟普通变量引用的行为完全不同。
结果before del, r(): <__main__.Widget object at 0x106229400> after del+gc, r(): None
验证:weakref.ref(w) 创建的r不会让Widget对象的引用计数+1——如果它会,那么del w之后对象的引用计数依然是1(还被r引用着),对象就不会被销毁,r()也就还能拿到原对象。但结果是del之后对象立刻被销毁,r()变成None——这正是弱引用的定义:它能"看到"对象,但不算在决定对象生死的引用计数里。
weakref.ref可以带一个回调参数。
代码与结果collected = [] def on_collect(ref): collected.append(True) r2 = weakref.ref(target, on_collect) del target gc.collect() print(collected) # 结果: [True]
回调on_collect在target对象被销毁的那一刻自动触发,收到的参数是弱引用对象本身(不是原对象,这时候原对象已经不存在了)——这正是很多缓存、资源池、监听器注销机制依赖的钩子:不需要在业务代码里显式调用"注销",对象真的没人再用了的那一刻,注册在弱引用上的清理逻辑会自动跑。
最常见的弱引用实战场景是给对象做缓存字典,又不想缓存本身导致对象永远不被回收。
结果d = weakref.WeakValueDictionary() d["k"] = obj before del: "k" in d = True, d.get("k") = <__main__.Big object> del obj gc.collect() after del: "k" in d = False
WeakValueDictionary的做法是只对value持有弱引用,一旦某个value对象在别处没有任何强引用了,这个键值对会自动从字典里消失,"k" in d直接变成False,不需要手动写清理逻辑去扫描哪些value已经失效——这正是本系列前面讲对象生命周期、GIL、引用计数这些话题时反复出现的同一个底层机制:Python对象的生死完全由引用计数(加上gc处理循环引用)决定,弱引用是唯一一种"能访问对象、但不介入这场生死判定"的引用方式。
每一步都是本文上面用weakref模块跑出来的原始结果。
weakref.ref / weakref.WeakValueDictionary:验证弱引用不增加引用计数、回调触发时机、自动清理失效key