A dict in which items get deleted if either the key or the value of the item is garbage collected.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | # By Eyal Lotem and Yair Chuchem, 2007
import weakref
class WeakKeyValueDict(object):
"""
A dict in which items are removed whenever either key or value are
garbage-collected.
"""
def __init__(self, *args, **kw):
init_dict = dict(*args, **kw)
self._d = weakref.WeakKeyDictionary(
(key, self._create_value(key, value))
for key, value in init_dict.iteritems())
def _create_value(self, key, value):
key_weakref = weakref.ref(key)
def value_collected(wr):
del self[key_weakref()]
return weakref.ref(value, value_collected)
def __getitem__(self, key):
return self._d[key]()
def __setitem__(self, key, value):
self._d[key] = self._create_value(key, value)
def __delitem__(self, key):
del self._d[key]
def __len__(self):
return len(self._d)
def __cmp__(self, other):
try:
other_iteritems = other.iteritems
except AttributeError:
return NotImplemented
return cmp(sorted(self.iteritems()),
sorted(other_iteritems()))
def __hash__(self):
raise TypeError("%s objects not hashable" % (self.__class__.__name__,))
def __contains__(self, key):
return key in self._d
def __iter__(self):
return self.iterkeys()
def iterkeys(self):
return self._d.iterkeys()
def keys(self):
return list(self.iterkeys())
def itervalues(self):
for value in self._d.itervalues():
yield value()
def values(self):
return list(self.itervalues())
def iteritems(self):
for key in self._d:
yield self._d[key]()
def items(self):
return list(self.iteritems())
def update(self, other):
for key, value in other.iteritems():
self[key] = value
def __repr__(self):
return repr(self._d)
def clear(self):
self._d.clear()
def copy(self):
return WeakKeyValueDict(self)
def get(self, key, default=None):
if key in self:
return self[key]
return default
def has_key(self, key):
return key in self
def pop(self, key, *args):
if args:
return self._pop_with_default(key, *args)
return self._pop(key)
def _pop(self, key):
return self._d.pop(key)()
def _pop_with_default(self, key, default):
if key in self:
return self._d.pop(key)
return default
def popitem(self):
key, value = self._d.popitem()
return key, value()
def setdefault(self, key, default):
if key in self:
return self[key]
self[key] = default
return default
|
The weakref module implements WeakKeyDictionary and WeakValueDictionary. Along with the builtin dict those are three out of four* combinations of dict weakness, so here is the missing combination. In several occasions we wanted it. At every time, instead of implementing it we solved the problem in a different way or figured out that it doesn't really helps us. Maybe it will help you.