python中的弱引用

时间:2012-03-28 12:57:47

标签: python python-2.7

我一直在试图理解python弱引用列表/字典的工作方式,并且也在阅读它的文档,但是我似乎无法弄清楚它们是如何工作的以及它们可以用于什么。任何人都可以给我一个基本的例子来说明他们的工作原理吗?非常感谢。

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

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

4 个答案:

答案 0 :(得分:52)

理论

引用计数通常如下:每次创建对象的引用时,它都会增加1,每当删除引用时,它都会减1。

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

引用计数由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.

答案 1 :(得分:20)

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

import weakref

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

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

答案 2 :(得分:10)

重点是它们允许将引用保留到对象,而不会阻止它们被垃圾回收。

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

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

答案 3 :(得分:0)

下面是比较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才能有效地删除对象。