Index: Doc/library/weakref.rst =================================================================== --- Doc/library/weakref.rst (Revision 58557) +++ Doc/library/weakref.rst (Arbeitskopie) @@ -28,24 +28,27 @@ 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 unbound), sets, frozensets, file objects, generators, type objects, DBcursor @@ -179,6 +182,12 @@ 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. Index: Lib/weakref.py =================================================================== --- Lib/weakref.py (Revision 58557) +++ Lib/weakref.py (Arbeitskopie) @@ -337,3 +337,108 @@ 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 Index: Lib/abc.py =================================================================== --- Lib/abc.py (Revision 58557) +++ Lib/abc.py (Arbeitskopie) @@ -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 @@ 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 @@ # 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 Index: Modules/Setup.dist =================================================================== --- Modules/Setup.dist (Revision 58557) +++ Modules/Setup.dist (Arbeitskopie) @@ -116,6 +116,7 @@ _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.