📄 compatsets.py
字号:
"""Classes to represent arbitrary sets (including sets of sets).This module implements sets using dictionaries whose values areignored. The usual operations (union, intersection, deletion, etc.)are provided as both methods and operators.Important: sets are not sequences! While they support 'x in s','len(s)', and 'for x in s', none of those operations are unique forsequences; for example, mappings support all three as well. Thecharacteristic operation for sequences is subscripting with smallintegers: s[i], for i in range(len(s)). Sets don't supportsubscripting at all. Also, sequences allow multiple occurrences andtheir elements have a definite order; sets on the other hand don'trecord multiple occurrences and don't remember the order of elementinsertion (which is why they don't support s[i]).The following classes are provided:BaseSet -- All the operations common to both mutable and immutable sets. This is an abstract class, not meant to be directly instantiated.Set -- Mutable sets, subclass of BaseSet; not hashable.ImmutableSet -- Immutable sets, subclass of BaseSet; hashable. An iterable argument is mandatory to create an ImmutableSet._TemporarilyImmutableSet -- Not a subclass of BaseSet: just a wrapper around a Set, hashable, giving the same hash value as the immutable set equivalent would have. Do not use this class directly.Only hashable objects can be added to a Set. In particular, you cannotreally add a Set as an element to another Set; if you try, what isactually added is an ImmutableSet built from it (it compares equal tothe one you tried adding).When you ask if `x in y' where x is a Set and y is a Set orImmutableSet, x is wrapped into a _TemporarilyImmutableSet z, andwhat's tested is actually `z in y'."""# Code history:## - Greg V. Wilson wrote the first version, using a different approach# to the mutable/immutable problem, and inheriting from dict.## - Alex Martelli modified Greg's version to implement the current# Set/ImmutableSet approach, and make the data an attribute.## - Guido van Rossum rewrote much of the code, made some API changes,# and cleaned up the docstrings.## - Raymond Hettinger added a number of speedups and other# improvements.__all__ = ['BaseSet', 'Set', 'ImmutableSet']try: True, Falseexcept NameError: # Maintain compatibility with Python 2.2 True, False = 1, 0class BaseSet(object): """Common base class for mutable and immutable sets.""" __slots__ = ['_data'] # Constructor def __init__(self): """This is an abstract class.""" # Don't call this from a concrete subclass! if self.__class__ is BaseSet: raise TypeError, ("BaseSet is an abstract class. " "Use Set or ImmutableSet.") # Standard protocols: __len__, __repr__, __str__, __iter__ def __len__(self): """Return the number of elements of a set.""" return len(self._data) def __repr__(self): """Return string representation of a set. This looks like 'Set([<list of elements>])'. """ return self._repr() # __str__ is the same as __repr__ __str__ = __repr__ def _repr(self, sorted=False): elements = self._data.keys() if sorted: elements.sort() return '%s(%r)' % (self.__class__.__name__, elements) def __iter__(self): """Return an iterator over the elements or a set. This is the keys iterator for the underlying dict. """ return self._data.iterkeys() # Equality comparisons using the underlying dicts def __eq__(self, other): self._binary_sanity_check(other) return self._data == other._data def __ne__(self, other): self._binary_sanity_check(other) return self._data != other._data # Copying operations def copy(self): """Return a shallow copy of a set.""" result = self.__class__() result._data.update(self._data) return result __copy__ = copy # For the copy module def __deepcopy__(self, memo): """Return a deep copy of a set; used by copy module.""" # This pre-creates the result and inserts it in the memo # early, in case the deep copy recurses into another reference # to this same set. A set can't be an element of itself, but # it can certainly contain an object that has a reference to # itself. from copy import deepcopy result = self.__class__() memo[id(self)] = result data = result._data value = True for elt in self: data[deepcopy(elt, memo)] = value return result # Standard set operations: union, intersection, both differences. # Each has an operator version (e.g. __or__, invoked with |) and a # method version (e.g. union). # Subtle: Each pair requires distinct code so that the outcome is # correct when the type of other isn't suitable. For example, if # we did "union = __or__" instead, then Set().union(3) would return # NotImplemented instead of raising TypeError (albeit that *why* it # raises TypeError as-is is also a bit subtle). def __or__(self, other): """Return the union of two sets as a new set. (I.e. all elements that are in either set.) """ if not isinstance(other, BaseSet): return NotImplemented result = self.__class__() result._data = self._data.copy() result._data.update(other._data) return result def union(self, other): """Return the union of two sets as a new set. (I.e. all elements that are in either set.) """ return self | other def __and__(self, other): """Return the intersection of two sets as a new set. (I.e. all elements that are in both sets.) """ if not isinstance(other, BaseSet): return NotImplemented if len(self) <= len(other): little, big = self, other else: little, big = other, self common = filter(big._data.has_key, little._data.iterkeys()) return self.__class__(common) def intersection(self, other): """Return the intersection of two sets as a new set. (I.e. all elements that are in both sets.) """ return self & other def __xor__(self, other): """Return the symmetric difference of two sets as a new set. (I.e. all elements that are in exactly one of the sets.) """ if not isinstance(other, BaseSet): return NotImplemented result = self.__class__() data = result._data value = True selfdata = self._data otherdata = other._data for elt in selfdata: if elt not in otherdata: data[elt] = value for elt in otherdata: if elt not in selfdata: data[elt] = value return result def symmetric_difference(self, other): """Return the symmetric difference of two sets as a new set. (I.e. all elements that are in exactly one of the sets.) """ return self ^ other def __sub__(self, other): """Return the difference of two sets as a new Set. (I.e. all elements that are in this set and not in the other.) """ if not isinstance(other, BaseSet): return NotImplemented result = self.__class__() data = result._data otherdata = other._data value = True for elt in self: if elt not in otherdata: data[elt] = value return result def difference(self, other): """Return the difference of two sets as a new Set. (I.e. all elements that are in this set and not in the other.) """ return self - other # Membership test def __contains__(self, element): """Report whether an element is a member of a set. (Called in response to the expression `element in self'.) """
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -