mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	 7b3ce6a17e
			
		
	
	
		7b3ce6a17e
		
	
	
	
	
		
			
			svn+ssh://pythondev@svn.python.org/python/trunk ........ r60441 | christian.heimes | 2008-01-30 12:46:00 +0100 (Wed, 30 Jan 2008) | 1 line Removed unused var ........ r60448 | christian.heimes | 2008-01-30 18:21:22 +0100 (Wed, 30 Jan 2008) | 1 line Fixed some references leaks in sys. ........ r60450 | christian.heimes | 2008-01-30 19:58:29 +0100 (Wed, 30 Jan 2008) | 1 line The previous change was causing a segfault after multiple calls to Py_Initialize() and Py_Finalize(). ........ r60463 | raymond.hettinger | 2008-01-30 23:17:31 +0100 (Wed, 30 Jan 2008) | 1 line Update itertool recipes ........ r60464 | christian.heimes | 2008-01-30 23:54:18 +0100 (Wed, 30 Jan 2008) | 1 line Bug #1234: Fixed semaphore errors on AIX 5.2 ........ r60469 | raymond.hettinger | 2008-01-31 02:38:15 +0100 (Thu, 31 Jan 2008) | 6 lines Fix defect in __ixor__ which would get the wrong answer if the input iterable had a duplicate element (two calls to toggle() reverse each other). Borrow the correct code from sets.py. ........ r60470 | raymond.hettinger | 2008-01-31 02:42:11 +0100 (Thu, 31 Jan 2008) | 1 line Missing return ........ r60471 | jeffrey.yasskin | 2008-01-31 08:44:11 +0100 (Thu, 31 Jan 2008) | 4 lines Added more documentation on how mixed-mode arithmetic should be implemented. I also noticed and fixed a bug in Rational's forward operators (they were claiming all instances of numbers.Rational instead of just the concrete types). ........
		
			
				
	
	
		
			592 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			592 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # Copyright 2007 Google, Inc. All Rights Reserved.
 | |
| # Licensed to PSF under a Contributor Agreement.
 | |
| 
 | |
| """Abstract Base Classes (ABCs) for collections, according to PEP 3119.
 | |
| 
 | |
| DON'T USE THIS MODULE DIRECTLY!  The classes here should be imported
 | |
| via collections; they are defined here only to alleviate certain
 | |
| bootstrapping issues.  Unit tests are in test_collections.
 | |
| """
 | |
| 
 | |
| from abc import ABCMeta, abstractmethod
 | |
| 
 | |
| __all__ = ["Hashable", "Iterable", "Iterator",
 | |
|            "Sized", "Container", "Callable",
 | |
|            "Set", "MutableSet",
 | |
|            "Mapping", "MutableMapping",
 | |
|            "MappingView", "KeysView", "ItemsView", "ValuesView",
 | |
|            "Sequence", "MutableSequence",
 | |
|            "ByteString",
 | |
|            "bytearray_iterator", "bytes_iterator", "dict_itemiterator",
 | |
|            "dict_items", "dict_keyiterator", "dict_keys", "dict_proxy",
 | |
|            "dict_valueiterator", "dict_values", "list_iterator",
 | |
|            "list_reverseiterator", "range_iterator", "set_iterator",
 | |
|            "str_iterator", "tuple_iterator", "zip_iterator",
 | |
|            ]
 | |
| 
 | |
| 
 | |
| ### collection related types which are not exposed through builtin ###
 | |
| ## iterators ##
 | |
| bytes_iterator = type(iter(b''))
 | |
| bytearray_iterator = type(iter(bytearray()))
 | |
| #callable_iterator = ???
 | |
| dict_keyiterator = type(iter({}.keys()))
 | |
| dict_valueiterator = type(iter({}.values()))
 | |
| dict_itemiterator = type(iter({}.items()))
 | |
| list_iterator = type(iter([]))
 | |
| list_reverseiterator = type(iter(reversed([])))
 | |
| range_iterator = type(iter(range(0)))
 | |
| set_iterator = type(iter(set()))
 | |
| str_iterator = type(iter(""))
 | |
| tuple_iterator = type(iter(()))
 | |
| zip_iterator = type(iter(zip()))
 | |
| ## views ##
 | |
| dict_keys = type({}.keys())
 | |
| dict_values = type({}.values())
 | |
| dict_items = type({}.items())
 | |
| ## misc ##
 | |
| dict_proxy = type(type.__dict__)
 | |
| 
 | |
| 
 | |
| ### ONE-TRICK PONIES ###
 | |
| 
 | |
| class Hashable(metaclass=ABCMeta):
 | |
| 
 | |
|     @abstractmethod
 | |
|     def __hash__(self):
 | |
|         return 0
 | |
| 
 | |
|     @classmethod
 | |
|     def __subclasshook__(cls, C):
 | |
|         if cls is Hashable:
 | |
|             for B in C.__mro__:
 | |
|                 if "__hash__" in B.__dict__:
 | |
|                     if B.__dict__["__hash__"]:
 | |
|                         return True
 | |
|                     break
 | |
|         return NotImplemented
 | |
| 
 | |
| 
 | |
| class Iterable(metaclass=ABCMeta):
 | |
| 
 | |
|     @abstractmethod
 | |
|     def __iter__(self):
 | |
|         while False:
 | |
|             yield None
 | |
| 
 | |
|     @classmethod
 | |
|     def __subclasshook__(cls, C):
 | |
|         if cls is Iterable:
 | |
|             if any("__iter__" in B.__dict__ for B in C.__mro__):
 | |
|                 return True
 | |
|         return NotImplemented
 | |
| 
 | |
| 
 | |
| class Iterator(metaclass=ABCMeta):
 | |
| 
 | |
|     @abstractmethod
 | |
|     def __next__(self):
 | |
|         raise StopIteration
 | |
| 
 | |
|     def __iter__(self):
 | |
|         return self
 | |
| 
 | |
|     @classmethod
 | |
|     def __subclasshook__(cls, C):
 | |
|         if cls is Iterator:
 | |
|             if any("__next__" in B.__dict__ for B in C.__mro__):
 | |
|                 return True
 | |
|         return NotImplemented
 | |
| 
 | |
| Iterator.register(bytes_iterator)
 | |
| Iterator.register(bytearray_iterator)
 | |
| #Iterator.register(callable_iterator)
 | |
| Iterator.register(dict_keyiterator)
 | |
| Iterator.register(dict_valueiterator)
 | |
| Iterator.register(dict_itemiterator)
 | |
| Iterator.register(list_iterator)
 | |
| Iterator.register(list_reverseiterator)
 | |
| Iterator.register(range_iterator)
 | |
| Iterator.register(set_iterator)
 | |
| Iterator.register(str_iterator)
 | |
| Iterator.register(tuple_iterator)
 | |
| Iterator.register(zip_iterator)
 | |
| 
 | |
| class Sized(metaclass=ABCMeta):
 | |
| 
 | |
|     @abstractmethod
 | |
|     def __len__(self):
 | |
|         return 0
 | |
| 
 | |
|     @classmethod
 | |
|     def __subclasshook__(cls, C):
 | |
|         if cls is Sized:
 | |
|             if any("__len__" in B.__dict__ for B in C.__mro__):
 | |
|                 return True
 | |
|         return NotImplemented
 | |
| 
 | |
| 
 | |
| class Container(metaclass=ABCMeta):
 | |
| 
 | |
|     @abstractmethod
 | |
|     def __contains__(self, x):
 | |
|         return False
 | |
| 
 | |
|     @classmethod
 | |
|     def __subclasshook__(cls, C):
 | |
|         if cls is Container:
 | |
|             if any("__contains__" in B.__dict__ for B in C.__mro__):
 | |
|                 return True
 | |
|         return NotImplemented
 | |
| 
 | |
| 
 | |
| class Callable(metaclass=ABCMeta):
 | |
| 
 | |
|     @abstractmethod
 | |
|     def __contains__(self, x):
 | |
|         return False
 | |
| 
 | |
|     @classmethod
 | |
|     def __subclasshook__(cls, C):
 | |
|         if cls is Callable:
 | |
|             if any("__call__" in B.__dict__ for B in C.__mro__):
 | |
|                 return True
 | |
|         return NotImplemented
 | |
| 
 | |
| 
 | |
| ### SETS ###
 | |
| 
 | |
| 
 | |
| class Set(metaclass=ABCMeta):
 | |
| 
 | |
|     """A set is a finite, iterable container.
 | |
| 
 | |
|     This class provides concrete generic implementations of all
 | |
|     methods except for __contains__, __iter__ and __len__.
 | |
| 
 | |
|     To override the comparisons (presumably for speed, as the
 | |
|     semantics are fixed), all you have to do is redefine __le__ and
 | |
|     then the other operations will automatically follow suit.
 | |
|     """
 | |
| 
 | |
|     @abstractmethod
 | |
|     def __contains__(self, value):
 | |
|         return False
 | |
| 
 | |
|     @abstractmethod
 | |
|     def __iter__(self):
 | |
|         while False:
 | |
|             yield None
 | |
| 
 | |
|     @abstractmethod
 | |
|     def __len__(self):
 | |
|         return 0
 | |
| 
 | |
|     def __le__(self, other):
 | |
|         if not isinstance(other, Set):
 | |
|             return NotImplemented
 | |
|         if len(self) > len(other):
 | |
|             return False
 | |
|         for elem in self:
 | |
|             if elem not in other:
 | |
|                 return False
 | |
|         return True
 | |
| 
 | |
|     def __lt__(self, other):
 | |
|         if not isinstance(other, Set):
 | |
|             return NotImplemented
 | |
|         return len(self) < len(other) and self.__le__(other)
 | |
| 
 | |
|     def __eq__(self, other):
 | |
|         if not isinstance(other, Set):
 | |
|             return NotImplemented
 | |
|         return len(self) == len(other) and self.__le__(other)
 | |
| 
 | |
|     @classmethod
 | |
|     def _from_iterable(cls, it):
 | |
|         return frozenset(it)
 | |
| 
 | |
|     def __and__(self, other):
 | |
|         if not isinstance(other, Iterable):
 | |
|             return NotImplemented
 | |
|         return self._from_iterable(value for value in other if value in self)
 | |
| 
 | |
|     def isdisjoint(self, other):
 | |
|         for value in other:
 | |
|             if value in self:
 | |
|                 return False
 | |
|         return True
 | |
| 
 | |
|     def __or__(self, other):
 | |
|         if not isinstance(other, Iterable):
 | |
|             return NotImplemented
 | |
|         return self._from_iterable(itertools.chain(self, other))
 | |
| 
 | |
|     def __sub__(self, other):
 | |
|         if not isinstance(other, Set):
 | |
|             if not isinstance(other, Iterable):
 | |
|                 return NotImplemented
 | |
|             other = self._from_iterable(other)
 | |
|         return self._from_iterable(value for value in self
 | |
|                                    if value not in other)
 | |
| 
 | |
|     def __xor__(self, other):
 | |
|         if not isinstance(other, Set):
 | |
|             if not isinstance(other, Iterable):
 | |
|                 return NotImplemented
 | |
|             other = self._from_iterable(other)
 | |
|         return (self - other) | (other - self)
 | |
| 
 | |
|     def _hash(self):
 | |
|         """Compute the hash value of a set.
 | |
| 
 | |
|         Note that we don't define __hash__: not all sets are hashable.
 | |
|         But if you define a hashable set type, its __hash__ should
 | |
|         call this function.
 | |
| 
 | |
|         This must be compatible __eq__.
 | |
| 
 | |
|         All sets ought to compare equal if they contain the same
 | |
|         elements, regardless of how they are implemented, and
 | |
|         regardless of the order of the elements; so there's not much
 | |
|         freedom for __eq__ or __hash__.  We match the algorithm used
 | |
|         by the built-in frozenset type.
 | |
|         """
 | |
|         MAX = sys.maxsize
 | |
|         MASK = 2 * MAX + 1
 | |
|         n = len(self)
 | |
|         h = 1927868237 * (n + 1)
 | |
|         h &= MASK
 | |
|         for x in self:
 | |
|             hx = hash(x)
 | |
|             h ^= (hx ^ (hx << 16) ^ 89869747)  * 3644798167
 | |
|             h &= MASK
 | |
|         h = h * 69069 + 907133923
 | |
|         h &= MASK
 | |
|         if h > MAX:
 | |
|             h -= MASK + 1
 | |
|         if h == -1:
 | |
|             h = 590923713
 | |
|         return h
 | |
| 
 | |
| Set.register(frozenset)
 | |
| 
 | |
| 
 | |
| class MutableSet(Set):
 | |
| 
 | |
|     @abstractmethod
 | |
|     def add(self, value):
 | |
|         """Return True if it was added, False if already there."""
 | |
|         raise NotImplementedError
 | |
| 
 | |
|     @abstractmethod
 | |
|     def discard(self, value):
 | |
|         """Return True if it was deleted, False if not there."""
 | |
|         raise NotImplementedError
 | |
| 
 | |
|     def remove(self, value):
 | |
|         """Remove an element. If not a member, raise a KeyError."""
 | |
|         if value not in self:
 | |
|             raise KeyError(value)
 | |
|         self.discard(value)
 | |
| 
 | |
|     def pop(self):
 | |
|         """Return the popped value.  Raise KeyError if empty."""
 | |
|         it = iter(self)
 | |
|         try:
 | |
|             value = it.__next__()
 | |
|         except StopIteration:
 | |
|             raise KeyError
 | |
|         self.discard(value)
 | |
|         return value
 | |
| 
 | |
|     def clear(self):
 | |
|         """This is slow (creates N new iterators!) but effective."""
 | |
|         try:
 | |
|             while True:
 | |
|                 self.pop()
 | |
|         except KeyError:
 | |
|             pass
 | |
| 
 | |
|     def __ior__(self, it: Iterable):
 | |
|         for value in it:
 | |
|             self.add(value)
 | |
|         return self
 | |
| 
 | |
|     def __iand__(self, c: Container):
 | |
|         for value in self:
 | |
|             if value not in c:
 | |
|                 self.discard(value)
 | |
|         return self
 | |
| 
 | |
|     def __ixor__(self, it: Iterable):
 | |
|         if not isinstance(it, Set):
 | |
|             it = self._from_iterable(it)
 | |
|         for value in it:
 | |
|             if value in self:
 | |
|                 self.discard(value)
 | |
|             else:
 | |
|                 self.add(value)
 | |
|         return self
 | |
| 
 | |
|     def __isub__(self, it: Iterable):
 | |
|         for value in it:
 | |
|             self.discard(value)
 | |
|         return self
 | |
| 
 | |
| MutableSet.register(set)
 | |
| 
 | |
| 
 | |
| ### MAPPINGS ###
 | |
| 
 | |
| 
 | |
| class Mapping(metaclass=ABCMeta):
 | |
| 
 | |
|     @abstractmethod
 | |
|     def __getitem__(self, key):
 | |
|         raise KeyError
 | |
| 
 | |
|     def get(self, key, default=None):
 | |
|         try:
 | |
|             return self[key]
 | |
|         except KeyError:
 | |
|             return default
 | |
| 
 | |
|     def __contains__(self, key):
 | |
|         try:
 | |
|             self[key]
 | |
|         except KeyError:
 | |
|             return False
 | |
|         else:
 | |
|             return True
 | |
| 
 | |
|     @abstractmethod
 | |
|     def __len__(self):
 | |
|         return 0
 | |
| 
 | |
|     @abstractmethod
 | |
|     def __iter__(self):
 | |
|         while False:
 | |
|             yield None
 | |
| 
 | |
|     def keys(self):
 | |
|         return KeysView(self)
 | |
| 
 | |
|     def items(self):
 | |
|         return ItemsView(self)
 | |
| 
 | |
|     def values(self):
 | |
|         return ValuesView(self)
 | |
| 
 | |
| 
 | |
| class MappingView(metaclass=ABCMeta):
 | |
| 
 | |
|     def __init__(self, mapping):
 | |
|         self._mapping = mapping
 | |
| 
 | |
|     def __len__(self):
 | |
|         return len(self._mapping)
 | |
| 
 | |
| 
 | |
| class KeysView(MappingView, Set):
 | |
| 
 | |
|     def __contains__(self, key):
 | |
|         return key in self._mapping
 | |
| 
 | |
|     def __iter__(self):
 | |
|         for key in self._mapping:
 | |
|             yield key
 | |
| 
 | |
| KeysView.register(dict_keys)
 | |
| 
 | |
| 
 | |
| class ItemsView(MappingView, Set):
 | |
| 
 | |
|     def __contains__(self, item):
 | |
|         key, value = item
 | |
|         try:
 | |
|             v = self._mapping[key]
 | |
|         except KeyError:
 | |
|             return False
 | |
|         else:
 | |
|             return v == value
 | |
| 
 | |
|     def __iter__(self):
 | |
|         for key in self._mapping:
 | |
|             yield (key, self._mapping[key])
 | |
| 
 | |
| ItemsView.register(dict_items)
 | |
| 
 | |
| 
 | |
| class ValuesView(MappingView):
 | |
| 
 | |
|     def __contains__(self, value):
 | |
|         for key in self._mapping:
 | |
|             if value == self._mapping[key]:
 | |
|                 return True
 | |
|         return False
 | |
| 
 | |
|     def __iter__(self):
 | |
|         for key in self._mapping:
 | |
|             yield self._mapping[key]
 | |
| 
 | |
| ValuesView.register(dict_values)
 | |
| 
 | |
| 
 | |
| class MutableMapping(Mapping):
 | |
| 
 | |
|     @abstractmethod
 | |
|     def __setitem__(self, key, value):
 | |
|         raise KeyError
 | |
| 
 | |
|     @abstractmethod
 | |
|     def __delitem__(self, key):
 | |
|         raise KeyError
 | |
| 
 | |
|     __marker = object()
 | |
| 
 | |
|     def pop(self, key, default=__marker):
 | |
|         try:
 | |
|             value = self[key]
 | |
|         except KeyError:
 | |
|             if default is self.__marker:
 | |
|                 raise
 | |
|             return default
 | |
|         else:
 | |
|             del self[key]
 | |
|             return value
 | |
| 
 | |
|     def popitem(self):
 | |
|         try:
 | |
|             key = next(iter(self))
 | |
|         except StopIteration:
 | |
|             raise KeyError
 | |
|         value = self[key]
 | |
|         del self[key]
 | |
|         return key, value
 | |
| 
 | |
|     def clear(self):
 | |
|         try:
 | |
|             while True:
 | |
|                 self.popitem()
 | |
|         except KeyError:
 | |
|             pass
 | |
| 
 | |
|     def update(self, other=(), **kwds):
 | |
|         if isinstance(other, Mapping):
 | |
|             for key in other:
 | |
|                 self[key] = other[key]
 | |
|         elif hasattr(other, "keys"):
 | |
|             for key in other.keys():
 | |
|                 self[key] = other[key]
 | |
|         else:
 | |
|             for key, value in other:
 | |
|                 self[key] = value
 | |
|         for key, value in kwds.items():
 | |
|             self[key] = value
 | |
| 
 | |
| MutableMapping.register(dict)
 | |
| 
 | |
| 
 | |
| ### SEQUENCES ###
 | |
| 
 | |
| 
 | |
| class Sequence(metaclass=ABCMeta):
 | |
| 
 | |
|     """All the operations on a read-only sequence.
 | |
| 
 | |
|     Concrete subclasses must override __new__ or __init__,
 | |
|     __getitem__, and __len__.
 | |
|     """
 | |
| 
 | |
|     @abstractmethod
 | |
|     def __getitem__(self, index):
 | |
|         raise IndexError
 | |
| 
 | |
|     @abstractmethod
 | |
|     def __len__(self):
 | |
|         return 0
 | |
| 
 | |
|     def __iter__(self):
 | |
|         i = 0
 | |
|         while True:
 | |
|             try:
 | |
|                 v = self[i]
 | |
|             except IndexError:
 | |
|                 break
 | |
|             yield v
 | |
|             i += 1
 | |
| 
 | |
|     def __contains__(self, value):
 | |
|         for v in self:
 | |
|             if v == value:
 | |
|                 return True
 | |
|         return False
 | |
| 
 | |
|     def __reversed__(self):
 | |
|         for i in reversed(range(len(self))):
 | |
|             yield self[i]
 | |
| 
 | |
|     def index(self, value):
 | |
|         for i, v in enumerate(self):
 | |
|             if v == value:
 | |
|                 return i
 | |
|         raise ValueError
 | |
| 
 | |
|     def count(self, value):
 | |
|         return sum(1 for v in self if v == value)
 | |
| 
 | |
| Sequence.register(tuple)
 | |
| Sequence.register(str)
 | |
| 
 | |
| 
 | |
| class ByteString(Sequence):
 | |
| 
 | |
|     """This unifies bytes and bytearray.
 | |
| 
 | |
|     XXX Should add all their methods.
 | |
|     """
 | |
| 
 | |
| ByteString.register(bytes)
 | |
| ByteString.register(bytearray)
 | |
| 
 | |
| 
 | |
| class MutableSequence(Sequence):
 | |
| 
 | |
|     @abstractmethod
 | |
|     def __setitem__(self, index, value):
 | |
|         raise IndexError
 | |
| 
 | |
|     @abstractmethod
 | |
|     def __delitem__(self, index):
 | |
|         raise IndexError
 | |
| 
 | |
|     @abstractmethod
 | |
|     def insert(self, index, value):
 | |
|         raise IndexError
 | |
| 
 | |
|     def append(self, value):
 | |
|         self.insert(len(self), value)
 | |
| 
 | |
|     def reverse(self):
 | |
|         n = len(self)
 | |
|         for i in range(n//2):
 | |
|             self[i], self[n-i-1] = self[n-i-1], self[i]
 | |
| 
 | |
|     def extend(self, values):
 | |
|         for v in values:
 | |
|             self.append(v)
 | |
| 
 | |
|     def pop(self, index=-1):
 | |
|         v = self[index]
 | |
|         del self[index]
 | |
|         return v
 | |
| 
 | |
|     def remove(self, value):
 | |
|         del self[self.index(value)]
 | |
| 
 | |
|     def __iadd__(self, values):
 | |
|         self.extend(values)
 | |
| 
 | |
| MutableSequence.register(list)
 | |
| MutableSequence.register(bytearray)  # Multiply inheriting, see ByteString
 |