[Python-3000-checkins] r58602 - in python/branches/py3k: Doc/library/weakref.rst Lib/abc.py Lib/weakref.py Modules/Setup.dist

georg.brandl python-3000-checkins at python.org
Tue Oct 23 08:26:46 CEST 2007


Author: georg.brandl
Date: Tue Oct 23 08:26:46 2007
New Revision: 58602

Modified:
   python/branches/py3k/Doc/library/weakref.rst
   python/branches/py3k/Lib/abc.py
   python/branches/py3k/Lib/weakref.py
   python/branches/py3k/Modules/Setup.dist
Log:
#1061 (mainly by Thomas Wouters): use weak sets for abc caches.


Modified: python/branches/py3k/Doc/library/weakref.rst
==============================================================================
--- python/branches/py3k/Doc/library/weakref.rst	(original)
+++ python/branches/py3k/Doc/library/weakref.rst	Tue Oct 23 08:26:46 2007
@@ -28,23 +28,26 @@
 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 @@
    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.

Modified: python/branches/py3k/Lib/abc.py
==============================================================================
--- python/branches/py3k/Lib/abc.py	(original)
+++ python/branches/py3k/Lib/abc.py	Tue Oct 23 08:26:46 2007
@@ -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

Modified: python/branches/py3k/Lib/weakref.py
==============================================================================
--- python/branches/py3k/Lib/weakref.py	(original)
+++ python/branches/py3k/Lib/weakref.py	Tue Oct 23 08:26:46 2007
@@ -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

Modified: python/branches/py3k/Modules/Setup.dist
==============================================================================
--- python/branches/py3k/Modules/Setup.dist	(original)
+++ python/branches/py3k/Modules/Setup.dist	Tue Oct 23 08:26:46 2007
@@ -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.


More information about the Python-3000-checkins mailing list