WeakValueDictionary保留对没有更多强引用的对象的引用

7
>>> from weakref import WeakValueDictionary
>>> class Foo(object):
...     pass
>>> foo = Foo()
>>> db = WeakValueDictionary()
>>> db['foo-id'] = foo
>>> del foo
>>> dict(db)
{'foo-id': <__main__.Foo object at 0x4dd946c>}

为什么会显示这个结果而不是一个空的字典?请注意,这段代码产生了我所期望的结果:
>>> db2 = WeakValueDictionary()
>>> db2['disposable-id'] = Foo()
>>> dict(db2)
{}

它在执行脚本时也表现出预期的行为(而不是交互式解释器):
from weakref import WeakValueDictionary
class Foo(object):
    pass
foo = Foo()
db = WeakValueDictionary()
db['foo-id'] = foo
del foo
print str(dict(foo))
# prints {}
3个回答

11

WeakValueDictionary 不能保证在没有普通引用时会删除条目。它保证的是不会阻止垃圾回收进程 - 你的对象是可被垃圾回收的,而不是已经被垃圾回收了。当垃圾回收发生时,该条目将消失。


4

如果你只是在交互式 shell 中尝试这个,我认为这与垃圾回收在该接口下的工作方式和全局范围操作有关。

尝试从脚本中运行:

foo.py

from weakref import WeakValueDictionary

class Foo(object):
    pass

f = Foo()
d = WeakValueDictionary()
d['f'] = f 

print dict(d)
del f 
print dict(d)

And then...

$ python foo.py

{'f': <__main__.Foo object at 0x101f496d0>}
{}

现在,试着在交互式Python shell中将操作移至函数范围内:
from weakref import WeakValueDictionary

class Foo(object):
    pass

f = Foo()
d = WeakValueDictionary()
d['f'] = f 

def main():
    global f
    print dict(d)
    del f 
    print dict(d)

main()

#{'f': <__main__.Foo object at 0x100479f10>}
#{}

我也尝试在交互式解释器中导入gc并在del foo后调用gc.collect(),它消除了弱引用。显然,交互式解释器不会立即收集垃圾。 - Jordan
是的。虽然我没有科学依据,但我认为交互式 shell 并不是可靠行为的最佳案例。它非常适合测试,但无法与简单的可执行脚本相比。 - jdi

3
在Python交互式Shell中,无论你声明了什么变量,都不会被自动垃圾回收,因为__main__作用域尚未结束。Python中的垃圾回收基于引用计数,除非你明确地进行垃圾回收或退出当前作用域,否则它不会被回收。
在同一个Shell中,如果你在函数内部实现了WeakRef逻辑,你将看到预期的结果,因为在函数完成后,控制流离开作用域,对象被垃圾回收。
这就是为什么@jdi的示例使用函数正好展示了你想要的东西。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接