[Python-checkins] r55279 - sandbox/trunk/abc/abc.py sandbox/trunk/abc/xyz.py
guido.van.rossum
python-checkins at python.org
Sat May 12 01:42:48 CEST 2007
Author: guido.van.rossum
Date: Sat May 12 01:42:40 2007
New Revision: 55279
Modified:
sandbox/trunk/abc/abc.py
sandbox/trunk/abc/xyz.py
Log:
Checkpoint.
Modified: sandbox/trunk/abc/abc.py
==============================================================================
--- sandbox/trunk/abc/abc.py (original)
+++ sandbox/trunk/abc/abc.py Sat May 12 01:42:40 2007
@@ -208,17 +208,16 @@
### SETS ###
-class Set(Sized, Iterable, Container, PartiallyOrdered):
+class Set(Sized, Iterable, Container):
"""A plain set is a finite, iterable container.
- This enables a generic implementation of equality and ordering based
- on set inclusion.
+ This class provides concrete generic implementations of all
+ methods except for __len__, __iter__ and __contains__.
- I don't see a use case for a non-iterable set that has a size.
-
- The idea here is that all you have to do is redefine __le__ and then
- the other operations will automatically follow suit.
+ 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.
"""
def __le__(self, other):
@@ -241,64 +240,46 @@
return NotImplemented
return len(self) == len(other) and self.__le__(other)
-
-class ComposableSet(Set):
-
- # XXX The following implementations of &, |, ^, - return frozen
- # sets because we have to pick a concrete type. They are allowed
- # to return any subclass of Set (but Set is not a concrete
- # implementation). We return frozen sets because returning set
- # may mislead callers from assuming that these operations always
- # return mutable sets.
-
- # XXX Alternatively, we might make these abstract.
-
- @staticmethod
- def fromiterable(it):
+ @classmethod
+ def _from_iterable(cls, it):
return frozenset(it)
def __and__(self, other):
if not isinstance(other, Iterable):
return NotImplemented
- return self.fromiterable(value for value in other if value in self)
+ return self._from_iterable(value for value in other if value in self)
def __or__(self, other):
- return self.fromiterable(itertools.chain(self, other))
+ if not isinstance(other, Iterable):
+ return NotImplemented
+ return self._from_iterable(itertools.chain(self, other))
- def __xor__(self, other):
+ def __sub__(self, other):
if not isinstance(other, Set):
if not isinstance(other, Iterable):
return NotImplemented
- other = self.fromiterable(other)
- return self.fromiterable(itertool.chain(
- (value for value in self if value not in other),
- (other for value in other if value not in self)))
+ other = self._from_iterable(other)
+ return self._from_iterable(value for value in self
+ if value not in other)
- def __sub__(self, other):
+ def __xor__(self, other):
if not isinstance(other, Set):
if not isinstance(other, Iterable):
return NotImplemented
- other = self.fromiterable(other)
- return self.fromiterable(value for value in self if value not in other)
-
+ other = self._from_iterable(other)
+ return (self - other) | (other - self)
-# XXX Should this derive from Set instead of from ComposableSet?
-class HashableSet(ComposableSet, Hashable):
-
- def __hash__(self):
+ def _hash(self):
"""The hash value must match __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 just XOR the hash of the elements.
-
- XXX This should match frozenset_hash() in Objects/setobject.c.
+ 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.
"""
- h = 0
- for elem in self:
- h ^= hash(elem)
- return h
+ # XXX This is not a very efficient implementation
+ return hash(frozenset(self))
# XXX Should this derive from Set instead of from ComposableSet?
@@ -365,10 +346,6 @@
return self
-# class set(Set)
-# class frozenset(HashableSet)
-
-
### MAPPINGS ###
Modified: sandbox/trunk/abc/xyz.py
==============================================================================
--- sandbox/trunk/abc/xyz.py (original)
+++ sandbox/trunk/abc/xyz.py Sat May 12 01:42:40 2007
@@ -103,6 +103,8 @@
raise TypeError("Can only register classes")
if issubclass(subclass, cls):
return # Already a subclass
+ # Subtle: test for cycles *after* testing for "already a subclass";
+ # this means we allow X.register(X) and interpret it as a no-op.
if issubclass(cls, subclass):
# This would create a cycle, which is bad for the algorithm below
raise RuntimeError("Refusing to create an inheritance cycle")
@@ -158,6 +160,8 @@
def _demo():
+ # Set up a bunch of trivial ABCs
+
class Sequence(metaclass=ABCMeta):
"""A sequence without any behavior implementation."""
@@ -199,6 +203,8 @@
Sequence.register(MutableSequence)
+ # Test them
+
SAMPLES = [0, b"", "", u"", [], (), {}, set(), frozenset()]
def show(abc):
@@ -214,6 +220,8 @@
Set, ImmutableSet, MutableSet]:
show(abc)
+ # Add another one at the bottom
+
class Collection(metaclass=ABCMeta):
"""A collection."""
@@ -222,24 +230,67 @@
Collection.register(Mapping)
Collection.register(Collection)
+ # And test it
+
for abc in [Collection]:
show(abc)
abc._dump_registry()
+ # Set up some tests for @abstractmethod
+
class A(metaclass=ABCMeta):
@abstractmethod
def foo(self): pass
- class C(A):
+ @abstractmethod
+ def bar(self): pass
+ class B(A):
def foo(self): pass
+ class C(B):
+ def bar(self): pass
try:
A()
+ assert False
except TypeError as err:
print("as expected:", err)
- else:
+ try:
+ B()
assert False
+ except TypeError as err:
+ print("as expected:", err)
C()
+ # Test a special Hashable
+
+ class Hashable:
+ @classmethod
+ def __instancecheck__(self, x):
+ return getattr(x, "__hash__", None) is not None
+ @classmethod
+ def __subclasscheck__(self, C):
+ if not hasattr(C, "__bases__"):
+ raise TypeError(
+ "%.100s object %.100r is not a class" %
+ (C.__class__.__name__, C))
+ return getattr(C, "__hash__", None) is not None
+
+ assert isinstance(42, Hashable)
+ assert not isinstance([], Hashable)
+ assert issubclass(tuple, Hashable)
+ assert issubclass(type, Hashable)
+ assert not issubclass(dict, Hashable)
+
+ assert isinstance(tuple, Hashable) # types are hashable
+
+ x = ([], {}) # Unhashable tuple
+ assert isinstance(x, Hashable) # Even though it raises TypeError
+
+ try:
+ issubclass(42, Hashable)
+ assert False
+ except TypeError as err:
+ print("as expected:", err)
+
if __name__ == "__main__":
_demo()
More information about the Python-checkins
mailing list