diff options
Diffstat (limited to 'Lib/weakref.py')
| -rw-r--r-- | Lib/weakref.py | 51 |
1 files changed, 40 insertions, 11 deletions
diff --git a/Lib/weakref.py b/Lib/weakref.py index 5d09497..aaebd0c 100644 --- a/Lib/weakref.py +++ b/Lib/weakref.py @@ -16,7 +16,8 @@ from _weakref import ( proxy, CallableProxyType, ProxyType, - ReferenceType) + ReferenceType, + _remove_dead_weakref) from _weakrefset import WeakSet, _IterationGuard @@ -111,7 +112,9 @@ class WeakValueDictionary(collections.MutableMapping): if self._iterating: self._pending_removals.append(wr.key) else: - del self.data[wr.key] + # Atomic removal is necessary since this function + # can be called asynchronously by the GC + _remove_dead_weakref(d, wr.key) self._remove = remove # A list of keys to be removed self._pending_removals = [] @@ -125,9 +128,12 @@ class WeakValueDictionary(collections.MutableMapping): # We shouldn't encounter any KeyError, because this method should # always be called *before* mutating the dict. while l: - del d[l.pop()] + key = l.pop() + _remove_dead_weakref(d, key) def __getitem__(self, key): + if self._pending_removals: + self._commit_removals() o = self.data[key]() if o is None: raise KeyError(key) @@ -140,9 +146,13 @@ class WeakValueDictionary(collections.MutableMapping): del self.data[key] def __len__(self): - return len(self.data) - len(self._pending_removals) + if self._pending_removals: + self._commit_removals() + return len(self.data) def __contains__(self, key): + if self._pending_removals: + self._commit_removals() try: o = self.data[key]() except KeyError: @@ -150,7 +160,7 @@ class WeakValueDictionary(collections.MutableMapping): return o is not None def __repr__(self): - return "<WeakValueDictionary at %s>" % id(self) + return "<%s at %#x>" % (self.__class__.__name__, id(self)) def __setitem__(self, key, value): if self._pending_removals: @@ -158,6 +168,8 @@ class WeakValueDictionary(collections.MutableMapping): self.data[key] = KeyedRef(value, self._remove, key) def copy(self): + if self._pending_removals: + self._commit_removals() new = WeakValueDictionary() for key, wr in self.data.items(): o = wr() @@ -169,6 +181,8 @@ class WeakValueDictionary(collections.MutableMapping): def __deepcopy__(self, memo): from copy import deepcopy + if self._pending_removals: + self._commit_removals() new = self.__class__() for key, wr in self.data.items(): o = wr() @@ -177,6 +191,8 @@ class WeakValueDictionary(collections.MutableMapping): return new def get(self, key, default=None): + if self._pending_removals: + self._commit_removals() try: wr = self.data[key] except KeyError: @@ -190,6 +206,8 @@ class WeakValueDictionary(collections.MutableMapping): return o def items(self): + if self._pending_removals: + self._commit_removals() with _IterationGuard(self): for k, wr in self.data.items(): v = wr() @@ -197,6 +215,8 @@ class WeakValueDictionary(collections.MutableMapping): yield k, v def keys(self): + if self._pending_removals: + self._commit_removals() with _IterationGuard(self): for k, wr in self.data.items(): if wr() is not None: @@ -214,10 +234,14 @@ class WeakValueDictionary(collections.MutableMapping): keep the values around longer than needed. """ + if self._pending_removals: + self._commit_removals() with _IterationGuard(self): yield from self.data.values() def values(self): + if self._pending_removals: + self._commit_removals() with _IterationGuard(self): for wr in self.data.values(): obj = wr() @@ -239,24 +263,27 @@ class WeakValueDictionary(collections.MutableMapping): try: o = self.data.pop(key)() except KeyError: + o = None + if o is None: if args: return args[0] - raise - if o is None: - raise KeyError(key) + else: + raise KeyError(key) else: return o def setdefault(self, key, default=None): try: - wr = self.data[key] + o = self.data[key]() except KeyError: + o = None + if o is None: if self._pending_removals: self._commit_removals() self.data[key] = KeyedRef(default, self._remove, key) return default else: - return wr() + return o def update(*args, **kwargs): if not args: @@ -287,6 +314,8 @@ class WeakValueDictionary(collections.MutableMapping): keep the values around longer than needed. """ + if self._pending_removals: + self._commit_removals() return list(self.data.values()) @@ -372,7 +401,7 @@ class WeakKeyDictionary(collections.MutableMapping): return len(self.data) - len(self._pending_removals) def __repr__(self): - return "<WeakKeyDictionary at %s>" % id(self) + return "<%s at %#x>" % (self.__class__.__name__, id(self)) def __setitem__(self, key, value): self.data[ref(key, self._remove)] = value |
