diff -r 17334c1d9245 Lib/weakref.py --- a/Lib/weakref.py Tue Oct 25 10:38:07 2016 +0300 +++ b/Lib/weakref.py Tue Oct 25 12:48:51 2016 +0300 @@ -86,6 +86,12 @@ class WeakMethod(ref): __hash__ = ref.__hash__ +def _atomic_del_ref(d, key): + if d[key]() is None: + wr = d.pop(key) + if wr() is not None: + print('BOO!!!') + class WeakValueDictionary(collections.MutableMapping): """Mapping class that references values weakly. @@ -111,7 +117,7 @@ class WeakValueDictionary(collections.Mu if self._iterating: self._pending_removals.append(wr.key) else: - del self.data[wr.key] + _atomic_del_ref(self.data, wr.key) self._remove = remove # A list of keys to be removed self._pending_removals = [] @@ -125,7 +131,7 @@ class WeakValueDictionary(collections.Mu # We shouldn't encounter any KeyError, because this method should # always be called *before* mutating the dict. while l: - del d[l.pop()] + _atomic_del_ref(d, l.pop()) def __getitem__(self, key): o = self.data[key]() @@ -137,10 +143,17 @@ class WeakValueDictionary(collections.Mu def __delitem__(self, key): if self._pending_removals: self._commit_removals() - del self.data[key] + o = self.data.pop(key)() + if o is None: + raise KeyError(key) def __len__(self): - return len(self.data) - len(self._pending_removals) + count = len(self.data) + if self._pending_removals: + for key in set(self._pending_removals): + if self.data[key]() is None: + count -= 1 + return count def __contains__(self, key): try: