0
0
mirror of https://github.com/python/cpython.git synced 2024-12-01 11:15:56 +01:00
cpython/Lib/_abcoll.py
Guido van Rossum 7eaf8223a0 Merged revisions 55962-56019 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/branches/p3yk

................
  r55985 | neal.norwitz | 2007-06-14 20:14:38 -0700 (Thu, 14 Jun 2007) | 2 lines

  All these tests have been flaky wrt reporting leaks.  Disable them.
................
  r56003 | neal.norwitz | 2007-06-15 19:41:09 -0700 (Fri, 15 Jun 2007) | 1 line

  Fix typo (certain).
................
  r56004 | neal.norwitz | 2007-06-15 20:54:18 -0700 (Fri, 15 Jun 2007) | 4 lines

  Fix it so test_os no longer reports ref leaks by clearing all the caches
  the ABCMeta stores on the class.  Apply this to all the ABC collections
  as well as the class of os.environ which inherits from an ABC collection.
................
  r56013 | neal.norwitz | 2007-06-17 19:56:31 -0700 (Sun, 17 Jun 2007) | 4 lines

  This should make it a little easier when adding new collections which use ABCs.
  The new subclass won't need to be listed in regrtest.
  It will be even better when Guido adds weakrefs. :-)
................
  r56014 | martin.v.loewis | 2007-06-17 20:15:51 -0700 (Sun, 17 Jun 2007) | 1 line

  Drop inline, as it's not support by VS 2003.
................
  r56015 | martin.v.loewis | 2007-06-17 20:17:19 -0700 (Sun, 17 Jun 2007) | 1 line

  Expect long objects for DWORD values.
................
  r56016 | martin.v.loewis | 2007-06-17 20:18:01 -0700 (Sun, 17 Jun 2007) | 1 line

  Drop modules that have been deleted.
................
  r56017 | martin.v.loewis | 2007-06-17 20:18:55 -0700 (Sun, 17 Jun 2007) | 1 line

  Bump DLL version number to 30.
................
  r56018 | neal.norwitz | 2007-06-17 20:55:43 -0700 (Sun, 17 Jun 2007) | 62 lines

  Merged revisions 55951-56013 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r55956 | thomas.heller | 2007-06-13 00:07:03 -0700 (Wed, 13 Jun 2007) | 2 lines

    Do not hardcode the buildbot's directory name.
  ........
    r55957 | thomas.heller | 2007-06-13 00:07:41 -0700 (Wed, 13 Jun 2007) | 2 lines

    Notes about building tcl/tk for windows/AMD64.
  ........
    r55958 | thomas.heller | 2007-06-13 00:54:57 -0700 (Wed, 13 Jun 2007) | 2 lines

    Build bzip2.
  ........
    r55962 | walter.doerwald | 2007-06-13 09:57:12 -0700 (Wed, 13 Jun 2007) | 8 lines

    Add T_PYSSIZET in structmember.h: This can be used for
    Py_ssize_t members.

    Simplify the implementation of UnicodeError objects:
    start and end attributes are now stored directly as
    Py_ssize_t members, which simplifies various get and
    set functions.
  ........
    r55975 | martin.v.loewis | 2007-06-14 13:46:25 -0700 (Thu, 14 Jun 2007) | 3 lines

    Patch #1734014: Use _I64_MAX instead of LLONG_MAX.
    Will backport to 2.5.
  ........
    r55984 | neal.norwitz | 2007-06-14 20:11:41 -0700 (Thu, 14 Jun 2007) | 4 lines

    urllib2_localnet says it leaks probably due to threads. So ignore it.
    popen2 is also complaining probably for similar reasons.
    make install always reports failure, so don't mail in this case.
  ........
    r56001 | andrew.kuchling | 2007-06-15 15:43:03 -0700 (Fri, 15 Jun 2007) | 1 line

    Add a word
  ........
    r56005 | martin.v.loewis | 2007-06-16 03:08:43 -0700 (Sat, 16 Jun 2007) | 2 lines

    Mention Senthil Kumaran.
  ........
    r56006 | georg.brandl | 2007-06-16 10:10:12 -0700 (Sat, 16 Jun 2007) | 2 lines

    Add missing \versionadded.
  ........
    r56009 | neal.norwitz | 2007-06-17 11:48:32 -0700 (Sun, 17 Jun 2007) | 1 line

    SF #1738670, make example in doc work
  ........
    r56011 | neal.norwitz | 2007-06-17 19:46:36 -0700 (Sun, 17 Jun 2007) | 1 line

    SF #1738754, remove extra backslash in string
  ........
    r56012 | neal.norwitz | 2007-06-17 19:50:15 -0700 (Sun, 17 Jun 2007) | 1 line

    Revert last change for SF #1738754, there's no print in there.
  ........
................
2007-06-18 17:58:50 +00:00

536 lines
12 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",
]
### 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
Iterable.register(bytes)
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
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 __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.maxint
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 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 toggle(self, value):
"""Return True if it was added, False if deleted."""
# XXX This implementation is not thread-safe
if value in self:
self.discard(value)
return False
else:
self.add(value)
return True
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):
# This calls toggle(), so if that is overridded, we call the override
for value in it:
self.toggle(it)
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(type({}.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(type({}.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(type({}.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(basestring)
Sequence.register(buffer)
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(bytes)