summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2007-10-23 06:26:46 (GMT)
committerGeorg Brandl <georg@python.org>2007-10-23 06:26:46 (GMT)
commit3b8cb17695209c48bfc618ba265d201e81d1603a (patch)
tree104dda0dd1ec84e9c8eacf05194cacb5698c9f36
parentb98dd2e5d2133b1c8cebd1dd221cf69eefeb154f (diff)
downloadcpython-3b8cb17695209c48bfc618ba265d201e81d1603a.zip
cpython-3b8cb17695209c48bfc618ba265d201e81d1603a.tar.gz
cpython-3b8cb17695209c48bfc618ba265d201e81d1603a.tar.bz2
#1061 (mainly by Thomas Wouters): use weak sets for abc caches.
-rw-r--r--Doc/library/weakref.rst35
-rw-r--r--Lib/abc.py9
-rw-r--r--Lib/weakref.py105
-rw-r--r--Modules/Setup.dist1
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.
diff --git a/Lib/abc.py b/Lib/abc.py
index f8e0230..54dc8e2 100644
--- a/Lib/abc.py
+++ b/Lib/abc.py
@@ -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.