弱引用模块,避免循环引用的GC问题,主要使用
WeakKeyDictionary,WeakValueDictionary,WeakSet,WeakMethod,finalize
ref,proxy,getweakrefcount,getweakrefs

WeakValueDictionary

实现一种可变映射,里面的value值是对象的弱引用,被引用的对象在程序中的其他地方被当作垃圾回收后,对应的键会自动从 WeakValueDictionary 中删除。因此,WeakValueDictionary 经常用于缓存。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from weakref import WeakValueDictionary

wd = WeakValueDictionary()


class T:
def __init__(self, v):
self.v = v


items = [T(i) for i in range(3)]
for item in items:
wd[item.v] = item

print(dict(wd))
del items[0]
print(dict(wd))
###
{0: <__main__.T object at 0x10b1427b8>, 1: <__main__.T object at 0x10b6d1588>, 2: <__main__.T object at 0x10b6d1860>}
{1: <__main__.T object at 0x10b6d1588>, 2: <__main__.T object at 0x10b6d1860>}

items[0]被回收,WeakValueDictionary中对应的key-value也被删除

WeakKeyDictionary

WeakValueDictionary类似,不过是key是对象的弱引用

WeakSet

Set的弱引用版本
官方示例:如果一个类需要知道所有实例,一种好的方案是创建一个 WeakSet 类型的类属性,保存实例的引用

WeakMethod

version>3.4
模拟对绑定方法的弱引用(即,在类上定义并在实例上查找的方法)。由于绑定方法是短暂的,因此标准的弱引用无法保持它。 WeakMethod有特殊代码重新创建绑定方法,直到对象或原始函数死亡

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import weakref



class T:
def __init__(self, v):
self.v = v

t= T(1)

wm1 = weakref.WeakMethod(t.__init__)
r1 = weakref.ref(t.__init__)
print(r1)
print(wm1)
###
<weakref at 0x1059f1188; dead> #r1已经标注dead,也就是obj被GC了
<weakref at 0x106c32b38; to 'T' at 0x1055b2828>

finalize

ref

ref(obj,callback),获取一个对象的弱引用,返回的是一个weakref类型,允许通过调用它来获取引用对象,对象被释放时调用callback。可以为一个对象构造多个弱引用,每个弱引用注册的回调将从最近注册的回调调用到最早注册的回调。传给回调的参数是弱引用对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import weakref


class T:
def __init__(self, v):
self.v = v


t = T(1)
r1 = weakref.ref(t)
print(r1)
print(type(r1))
print(type(r1()))
###
<weakref at 0x10cd09458; to 'T' at 0x10c8ca828>
<class 'weakref'>
<class '__main__.T'>

proxy

proxy(obj,callback),获取一个对象的代理对象,返回的是一个ProxyType或者CallableProxyType,可以直接当原对象使用,对象被释放时调用callback
ref创建的弱引用区别,如果被引用对象被删除,ref会返回None,而proxy则会报错:weakref.ReferenceError

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import weakref


class T:
def __init__(self, v):
self.v = v


t = T(1)
r1 = weakref.ref(t)
wm1 = weakref.proxy(t)
print(r1)
print(wm1)
###
<weakref at 0x10625d408; to 'T' at 0x105e1e828>
<__main__.T object at 0x105e1e828>

getweakrefcount

getweakrefcount(obj),返回引用object的弱引用和代理的数量。

getweakrefs

getweakrefs(obj),返回引用object的弱引用和代理的list