#1061 (mainly by Thomas Wouters): use weak sets for abc caches.

This commit is contained in:
Georg Brandl 2007-10-23 06:26:46 +00:00
parent b98dd2e5d2
commit 3b8cb17695
4 changed files with 133 additions and 17 deletions

View File

@ -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 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 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 would remain alive just because they appeared as values or keys in the
dictionaries. The :class:`WeakKeyDictionary` and :class:`WeakValueDictionary` dictionaries. The :class:`WeakKeyDictionary`, :class:`WeakValueDictionary`
classes supplied by the :mod:`weakref` module are an alternative, using weak and :class:`WeakSet` classes supplied by the :mod:`weakref` module are an
references to construct mappings that don't keep objects alive solely because alternative, using weak references to construct mappings that don't keep objects
they appear in the mapping objects. If, for example, an image object is a value alive solely because they appear in the container objects.
in a :class:`WeakValueDictionary`, then when the last remaining references to If, for example, an image object is a value in a :class:`WeakValueDictionary`,
that image object are the weak references held by weak mappings, garbage then when the last remaining references to that image object are the weak
collection can reclaim the object, and its corresponding entries in weak references held by weak mappings, garbage collection can reclaim the object,
mappings are simply deleted. and its corresponding entries in weak mappings are simply deleted.
:class:`WeakKeyDictionary` and :class:`WeakValueDictionary` use weak references :class:`WeakKeyDictionary` and :class:`WeakValueDictionary` use weak references
in their implementation, setting up callback functions on the 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 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 garbage collection. :class:`WeakSet` implements the :class:`set` interface,
dictionary types is all they need -- it's not usually necessary to create your but keeps weak references to its elements, just like a
own weak references directly. The low-level machinery used by the weak :class:`WeakKeyDictionary` does.
dictionary implementations is exposed by the :mod:`weakref` module for the
benefit of advanced uses. 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 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 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. 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 .. data:: ReferenceType
The type object for weak references objects. The type object for weak references objects.

View File

@ -3,6 +3,7 @@
"""Abstract Base Classes (ABCs) according to PEP 3119.""" """Abstract Base Classes (ABCs) according to PEP 3119."""
from weakref import WeakSet
def abstractmethod(funcobj): def abstractmethod(funcobj):
"""A decorator indicating abstract methods. """A decorator indicating abstract methods.
@ -130,9 +131,9 @@ class ABCMeta(type):
abstracts.add(name) abstracts.add(name)
cls.__abstractmethods__ = abstracts cls.__abstractmethods__ = abstracts
# Set up inheritance registry # Set up inheritance registry
cls._abc_registry = set() cls._abc_registry = WeakSet()
cls._abc_cache = set() cls._abc_cache = WeakSet()
cls._abc_negative_cache = set() cls._abc_negative_cache = WeakSet()
cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter
return cls return cls
@ -172,7 +173,7 @@ class ABCMeta(type):
# Check negative cache; may have to invalidate # Check negative cache; may have to invalidate
if cls._abc_negative_cache_version < ABCMeta._abc_invalidation_counter: if cls._abc_negative_cache_version < ABCMeta._abc_invalidation_counter:
# Invalidate the negative cache # Invalidate the negative cache
cls._abc_negative_cache = set() cls._abc_negative_cache = WeakSet()
cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter
elif subclass in cls._abc_negative_cache: elif subclass in cls._abc_negative_cache:
return False return False

View File

@ -337,3 +337,108 @@ class WeakKeyDictionary(UserDict.UserDict):
d[ref(key, self._remove)] = value d[ref(key, self._remove)] = value
if len(kwargs): if len(kwargs):
self.update(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

View File

@ -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 _sre _sre.c # Fredrik Lundh's new regular expressions
_codecs _codecsmodule.c # access to the builtin codecs and codec registry _codecs _codecsmodule.c # access to the builtin codecs and codec registry
_fileio _fileio.c # Standard I/O baseline _fileio _fileio.c # Standard I/O baseline
_weakref _weakref.c # weak references
# The zipimport module is always imported at startup. Having it as a # The zipimport module is always imported at startup. Having it as a
# builtin module avoids some bootstrapping problems and reduces overhead. # builtin module avoids some bootstrapping problems and reduces overhead.