我一直在试图理解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
答案 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)
下面是比较dict
和WeakValueDictionary
的示例:
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
才能有效地删除对象。