diff options
-rw-r--r-- | Doc/library/weakref.rst | 35 | ||||
-rw-r--r-- | Lib/abc.py | 9 | ||||
-rw-r--r-- | Lib/weakref.py | 105 | ||||
-rw-r--r-- | Modules/Setup.dist | 1 |
4 files changed, 133 insertions, 17 deletions
diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst index 940e064..299b818 100644 --- a/Doc/library/weakref.rst +++ b/Doc/library/weakref.rst @@ -28,23 +28,26 @@ it appears in a cache or mapping. For example, if you have a number of large binary image objects, you may wish to associate a name with each. If you used a Python dictionary to map names to images, or images to names, the image objects would remain alive just because they appeared as values or keys in the -dictionaries. The :class:`WeakKeyDictionary` and :class:`WeakValueDictionary` -classes supplied by the :mod:`weakref` module are an alternative, using weak -references to construct mappings that don't keep objects alive solely because -they appear in the mapping objects. If, for example, an image object is a value -in a :class:`WeakValueDictionary`, then when the last remaining references to -that image object are the weak references held by weak mappings, garbage -collection can reclaim the object, and its corresponding entries in weak -mappings are simply deleted. +dictionaries. The :class:`WeakKeyDictionary`, :class:`WeakValueDictionary` +and :class:`WeakSet` classes supplied by the :mod:`weakref` module are an +alternative, using weak references to construct mappings that don't keep objects +alive solely because they appear in the container objects. +If, for example, an image object is a value in a :class:`WeakValueDictionary`, +then when the last remaining references to that image object are the weak +references held by weak mappings, garbage collection can reclaim the object, +and its corresponding entries in weak mappings are simply deleted. :class:`WeakKeyDictionary` and :class:`WeakValueDictionary` use weak references in their implementation, setting up callback functions on the weak references that notify the weak dictionaries when a key or value has been reclaimed by -garbage collection. Most programs should find that using one of these weak -dictionary types is all they need -- it's not usually necessary to create your -own weak references directly. The low-level machinery used by the weak -dictionary implementations is exposed by the :mod:`weakref` module for the -benefit of advanced uses. +garbage collection. :class:`WeakSet` implements the :class:`set` interface, +but keeps weak references to its elements, just like a +:class:`WeakKeyDictionary` does. + +Most programs should find that using one of these weak container types is all +they need -- it's not usually necessary to create your own weak references +directly. The low-level machinery used by the weak dictionary implementations +is exposed by the :mod:`weakref` module for the benefit of advanced uses. Not all objects can be weakly referenced; those objects which can include class instances, functions written in Python (but not in C), methods (both bound and @@ -179,6 +182,12 @@ methods of :class:`WeakKeyDictionary` objects. Return a list of weak references to the values. +.. class:: WeakSet([elements]) + + Set class that keeps weak references to its elements. An element will be + discarded when no strong reference to it exists any more. + + .. data:: ReferenceType The type object for weak references objects. @@ -3,6 +3,7 @@ """Abstract Base Classes (ABCs) according to PEP 3119.""" +from weakref import WeakSet def abstractmethod(funcobj): """A decorator indicating abstract methods. @@ -130,9 +131,9 @@ class ABCMeta(type): abstracts.add(name) cls.__abstractmethods__ = abstracts # Set up inheritance registry - cls._abc_registry = set() - cls._abc_cache = set() - cls._abc_negative_cache = set() + cls._abc_registry = WeakSet() + cls._abc_cache = WeakSet() + cls._abc_negative_cache = WeakSet() cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter return cls @@ -172,7 +173,7 @@ class ABCMeta(type): # Check negative cache; may have to invalidate if cls._abc_negative_cache_version < ABCMeta._abc_invalidation_counter: # Invalidate the negative cache - cls._abc_negative_cache = set() + cls._abc_negative_cache = WeakSet() cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter elif subclass in cls._abc_negative_cache: return False diff --git a/Lib/weakref.py b/Lib/weakref.py index c5e5247..c54a072 100644 --- a/Lib/weakref.py +++ b/Lib/weakref.py @@ -337,3 +337,108 @@ class WeakKeyDictionary(UserDict.UserDict): d[ref(key, self._remove)] = value if len(kwargs): self.update(kwargs) + + +class WeakSet: + def __init__(self, data=None): + self.data = set() + def _remove(item, selfref=ref(self)): + self = selfref() + if self is not None: + self.data.discard(item) + self._remove = _remove + if data is not None: + self.update(data) + + def __iter__(self): + for itemref in self.data: + item = itemref() + if item is not None: + yield item + + def __contains__(self, item): + return ref(item) in self.data + + def __reduce__(self): + return (self.__class__, (list(self),), + getattr(self, '__dict__', None)) + + def add(self, item): + self.data.add(ref(item, self._remove)) + + def clear(self): + self.data.clear() + + def copy(self): + return self.__class__(self) + + def pop(self): + while True: + itemref = self.data.pop() + item = itemref() + if item is not None: + return item + + def remove(self, item): + self.data.remove(ref(item)) + + def discard(self, item): + self.data.discard(ref(item)) + + def update(self, other): + if isinstance(other, self.__class__): + self.data.update(other.data) + else: + for element in other: + self.add(element) + __ior__ = update + + # Helper functions for simple delegating methods. + def _apply(self, other, method): + if not isinstance(other, self.__class__): + other = self.__class__(other) + newdata = method(other.data) + newset = self.__class__() + newset.data = newdata + return newset + + def _apply_mutate(self, other, method): + if not isinstance(other, self.__class__): + other = self.__class__(other) + method(other) + + def difference(self, other): + return self._apply(other, self.data.difference) + __sub__ = difference + + def difference_update(self, other): + self._apply_mutate(self, self.data.difference_update) + __isub__ = difference_update + + def intersection(self, other): + return self._apply(other, self.data.intersection) + __and__ = intersection + + def intersection_update(self, other): + self._apply_mutate(self, self.data.intersection_update) + __iand__ = intersection_update + + def issubset(self, other): + return self.data.issubset(ref(item) for item in other) + __lt__ = issubset + + def issuperset(self, other): + return self.data.issuperset(ref(item) for item in other) + __gt__ = issuperset + + def symmetric_difference(self, other): + return self._apply(other, self.data.symmetric_difference) + __xor__ = symmetric_difference + + def symmetric_difference_update(self, other): + self._apply_mutate(other, self.data.symmetric_difference_update) + __ixor__ = symmetric_difference_update + + def union(self, other): + self._apply_mutate(other, self.data.union) + __or__ = union diff --git a/Modules/Setup.dist b/Modules/Setup.dist index 17445d5..ea1b806 100644 --- a/Modules/Setup.dist +++ b/Modules/Setup.dist @@ -116,6 +116,7 @@ pwd pwdmodule.c # this is needed to find out the user's home dir _sre _sre.c # Fredrik Lundh's new regular expressions _codecs _codecsmodule.c # access to the builtin codecs and codec registry _fileio _fileio.c # Standard I/O baseline +_weakref _weakref.c # weak references # The zipimport module is always imported at startup. Having it as a # builtin module avoids some bootstrapping problems and reduces overhead. |