Python 中的弱引用

我一直试图理解 python 弱引用列表/字典是如何工作的。我已经阅读了它的文档,但是我不能弄清楚它们是如何工作的,以及它们可以用来做什么。有没有人能给我举个简单的例子,解释一下它们是怎么工作的?

(编辑) 使用 Thomas 的代码,当我用 obj 代替 [1,2,3]时,它会抛出:

Traceback (most recent call last):
File "C:/Users/nonya/Desktop/test.py", line 9, in <module>
r = weakref.ref(obj)
TypeError: cannot create weak reference to 'list' object
36518 次浏览

关键是,它们允许保留对对象的引用,而不会阻止对它们进行垃圾收集。

这样做的两个主要原因是你需要自己做周期性的资源管理,例如关闭文件,但是因为这样的传递之间的时间可能很长,垃圾收集器可能会为你做这件事; 或者你创建了一个对象,可能相对昂贵的跟踪它在程序中的位置,但是你仍然需要处理实际存在的实例。

第二种情况可能更为常见——当您持有例如要通知的对象列表,并且您不希望通知系统阻止垃圾收集时,这种情况是合适的。

理论

引用计数通常是这样工作的: 每次创建对对象的引用时,它都会增加一个,每次删除引用时,它都会减少一个。

弱引用允许您创建对不会增加引用计数的对象的引用。

引用计数由 python 的垃圾收集器在运行时使用: 任何引用计数为0的对象都将被垃圾收集。

对于代价高昂的对象,可以使用弱引用,或者避免使用循环引用(尽管垃圾收集器通常自己完成这项工作)。

用法

下面是一个演示它们用法的示例:

import weakref
import gc


class MyObject(object):
def my_method(self):
print 'my_method was called!'


obj = MyObject()
r = weakref.ref(obj)


gc.collect()
assert r() is obj #r() allows you to access the object referenced: it's there.


obj = 1 #Let's change what obj references to
gc.collect()
assert r() is None #There is no object left: it was gc'ed.

我只是想指出,owre.ref 不适用于内置 list,因为 list 的 __slots__中没有 __weakref__。 例如,下面的代码定义了一个支持弱参数的列表容器。

import weakref


class weaklist(list):
__slots__ = ('__weakref__',)


l = weaklist()
r = weakref.ref(l)

下面是比较 dictWeakValueDictionary的例子:

class C: pass
ci=C()
print(ci)


wvd = weakref.WeakValueDictionary({'key' : ci})
print(dict(wvd), len(wvd)) #1
del ci
print(dict(wvd), len(wvd)) #0


ci2=C()
d=dict()
d['key']=ci2
print(d, len(d))
del ci2
print(d, len(d))

输出如下:

<__main__.C object at 0x00000213775A1E10>
{'key': <__main__.C object at 0x00000213775A1E10>} 1
{} 0
{'key': <__main__.C object at 0x0000021306B0E588>} 1
{'key': <__main__.C object at 0x0000021306B0E588>} 1

注意,在第一种情况下,一旦我们 del ci,实际的对象也将从字典 wvd中删除。

在这种情况下,或者在常规 Python 字典 dict类中,我们可以尝试删除对象,但是它仍然会在那里,如图所示。


注意: 如果我们使用 del,我们不调用 gc.collect()之后,因为只有 del有效地删除对象。