>>> 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>}
Why does it show this instead of an empty dictionary? Note that this code produces the result I'd expect:
>>> db2 = WeakValueDictionary()
>>> db2['disposable-id'] = Foo()
>>> dict(db2)
{}
It also behaves as expected when executing a script (instead of the interactive interpreter):
from weakref import WeakValueDictionary
class Foo(object):
pass
foo = Foo()
db = WeakValueDictionary()
db['foo-id'] = foo
del foo
print str(dict(foo))
# prints {}
In Python Interactive Shell, whatever variable you declare, is not garbage collected automatically, since the scope in
__main__
has not ended. Garbage collection in Python is based on reference count, and until you do it explicitly or get off the current scope, it won't be collected.In same shell, if you implement your
WeakRef
logic inside function, you will see the expected result, since upon finishing function, controls gets out of scope and objects are collected by garbage.That's why example by @jdi with function is showing you exactly what you want.
If you have only been trying this in an interactive shell, I believe it has to do with the way the garbage collection is working under that interface and the global scope operations.
Try this from a script:
foo.py
And then...
Now, try this from an interactive python shell, moving the operation under a functions scope:
WeakValueDictionary
does not guarantee that entries will be removed when there are no normal references. What it guarantees is that it will not prevent garbage collection in due course - your object is garbage collectable, not garbage collected. The entry will disappear when garbage collection happens.