[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