弱引用:不会增加对象的引用数量,不会妨碍所指对象(referent)被当作垃圾回收。弱引用可用于解决循环引用的问题。
弱引用在缓存应用中很有用,因为不想仅仅因为对象被缓存引用着而始终被保持。
通过调用 weakref 模块的 ref(obj[,callback]) 来创建一个弱引用,obj 是你想弱引用的对象, callback 是一个可选的函数,当因没有引用导致 Python 要销毁这个对象时调用。回调函数callback要求单个参数(弱引用的对象)。
一旦你有了一个对象的弱引用,你就能通过调用弱引用来获取被弱引用的对象。
>>> import sys
>>> import weakref
>>> class Man():
... def __init__(self, name):
... self.name = name
...
>>> man0 = Man('zhe') # 增加一个引用 count = 1
>>> sys.getrefcount(man0)
2
>>> r = weakref.ref(man0) # 增加一个弱引用 count = 1
>>> sys.getrefcount(man0)
2
>>> r # 获取弱引用所指向的对象
<weakref at 0x0000026AF3974688; to 'Man' at 0x0000026AF398C710>
>>> man1 = r()
>>> man0 is man1
True
>>> sys.getrefcount(man0)
3
>>> man0 = None
>>> man1 = None
>>> r # 当对象引用计数为零时,弱引用失效。
<weakref at 0x0000026AF3974688; dead>
weakref.ref 类的实例获取所指对象,提供的是底层接口,尽量不要手动创建并处理weakref.ref实例。
注:
代理对象 是弱引用对象,它们的行为就像它们所引用的对象,这就便于你不必首先调用弱引用来访问背后的对象。通过weakref模块的proxy(obj[,callback])函数来创建代理对象。使用代理对象就如同使用对象本身一样:
相比于创建弱引用 在调用上完全等同于
>>> import sys
>>> import weakref
>>> class Man():
... def __init__(self, name):
... self.name = name
...
>>> def callback_ref(self):
... print (self)
... print ("callback_ref")
...
>>> def callback_proxy(self):
... print (self)
... print ("callback_proxy")
...
>>> man = Man('zhe') # 引用计数 +1
>>> sys.getrefcount(man)
2
>>> man_ref = weakref.ref(man, callback_ref) # 弱引用 引用计数不变
>>> sys.getrefcount(man)
2
>>> man_ref # 弱引用对象
<weakref at 0x0000019A63664638; to 'Man' at 0x0000019A6367C668>
>>> man_ref.name # 对原对象的访问形式错误
Traceback (most recent call last):
File "" , line 1, in <module>
AttributeError: 'weakref' object has no attribute 'name'
>>> man_ref().name # 正确的对原对象的访问形式
'zhe'
>>> man_proxy = weakref.proxy(man, callback_proxy) # 使用代理 引用计数不变
>>> sys.getrefcount(man)
2
>>> man_proxy # 代理对象
<weakproxy at 0x0000019A634D6BD8 to Man at 0x0000019A6367C668>
>>> man_proxy.name # 访问形式与原引用相同
'zhe'
>>> del man # 注
Exception ignored in: <function callback_proxy at 0x0000019A636807B8>
Traceback (most recent call last):
File "" , line 2, in callback_proxy
ReferenceError: weakly-referenced object no longer exists
<weakref at 0x0000019A63664638; dead>
callback_ref
一般不要直接创建处理 weakref.ref 实例,最好使用 weakref 集合和 finalize,即 WeakKeyDictionary、WeakValueDictionary、WeakSet、finalize。
WeakValueDictionary 类实现的是一种可变映射,值是对象的弱引用,被引用的对象被回收后,对应的键会主动删除,常用于缓存。
import weakref
class Cheese:
def __init__(self, kind):
self.kind = kind
def __repr__(self):
return 'Cheese(%r)' % self.kind
stock = weakref.WeakValueDictionary()
catalog = [Cheese('A'), Cheese('B'), Cheese('C'), Cheese('D')]
for cheese in catalog:
stock[cheese.kind] = cheese
# for key in stock.keys():
# print(key)
print(sorted(stock.keys()))
# 删除了 catalog 列表,对应的值弱引用字典中对应的键被删除,但是 'D' 还存在一个引用,for循环中的 cheese,它是全局变量
del catalog
print(sorted(stock.keys()))
# 删除了 cheese 之后,所有键被删除
del cheese
print(sorted(stock.keys()))
"""
运行结果:
['A', 'B', 'C', 'D']
['D']
[]
Process finished with exit code 0
"""
WeakKeyDictionary与WeakValueDictionary对应,它存储的键是对象的弱引用。
import weakref
class Cheese:
def __init__(self, kind):
self.kind = kind
def __repr__(self):
return 'Cheese(%r)' % self.kind
stock = weakref.WeakKeyDictionary()
catalog = [Cheese('A'), Cheese('B'), Cheese('C'), Cheese('D')]
for cheese in catalog:
stock[cheese] = cheese.kind
# for value in stock.values():
# print(value)
print(sorted(stock.values()))
# 删除了 catalog 列表,对应的键弱引用字典中对应的值被删除,但是 'D' 还存在一个引用,for循环中的 cheese,它是全局变量
del catalog
print(sorted(stock.values()))
# 删除了 cheese 之后,所有键被删除
del cheese
print(sorted(stock.values()))
"""
运行结果:
['A', 'B', 'C', 'D']
['D']
[]
Process finished with exit code 0
"""
import weakref
class Cheese:
def __init__(self, kind):
self.kind = kind
def __repr__(self):
return 'Cheese(%r)' % self.kind
a = Cheese("zhangsan")
b = Cheese("lisi")
c = Cheese("wangwu")
d = Cheese("zhaoliu")
weak_set = weakref.WeakSet()
weak_set.add(a)
weak_set.add(b)
weak_set.add(c)
weak_set.add(d)
for item in weak_set:
print(item)
print(weak_set.pop())
"""
运行结果:
Cheese('wangwu')
Cheese('zhangsan')
Cheese('lisi')
Cheese('zhaoliu')
Cheese('wangwu')
Process finished with exit code 0
"""
操作可参照普通集合的成员方法。
[参考博客]
https://www.jianshu.com/p/6cc7a98fdb81
https://www.baidu.com/link?url=drZfhkNPyI4NpZYAtsdwkn7svlXG6wn3cubwGFUgoYhG58h-nWKXb5N71P-h-Io2pvJjliPvuqxeM15XIsQorkGlHb7GwsfEjhYQsYkA50S&wd=&eqid=ac3662e2001b203f000000035f0d4fe2