[Python-checkins] r54887 - sandbox/trunk/abc/abc.py

guido.van.rossum python-checkins at python.org
Fri Apr 20 20:17:19 CEST 2007


Author: guido.van.rossum
Date: Fri Apr 20 20:17:18 2007
New Revision: 54887

Modified:
   sandbox/trunk/abc/abc.py
Log:
Do more of the work for abstract class detection in the metaclass.
Use Finite instead of Sizeable.


Modified: sandbox/trunk/abc/abc.py
==============================================================================
--- sandbox/trunk/abc/abc.py	(original)
+++ sandbox/trunk/abc/abc.py	Fri Apr 20 20:17:18 2007
@@ -17,6 +17,9 @@
 import sys
 
 
+### ABC SUPPORT ###
+
+
 def abstractmethod(funcobj):
     """A decorator indicating abstract methods.
 
@@ -42,7 +45,7 @@
             def my_abstract_class_method(self, ...):
                 ...
     """
-    funcobj.__abstractmethod__ = True
+    funcobj.__isabstractmethod__ = True
     return funcobj
 
 
@@ -52,12 +55,14 @@
 
     def __new__(mcls, name, bases, namespace):
         cls = super(AbstractClass, mcls).__new__(mcls, name, bases, namespace)
-        abstracts = set()
+        abstracts = {name
+                     for name, value in namespace.items()
+                     if getattr(value, "__isabstractmethod__", False)}
         for base in bases:
-            abstracts.update(getattr(base, "__abstractmethods__", set()))
-        for name, value in namespace.items():
-            if getattr(value, "__abstractmethod__", False):
-                abstracts.add(name)
+            for name in getattr(base, "__abstractmethods__", set()):
+                value = getattr(cls, name, None)
+                if getattr(value, "__isabstractmethod__", False):
+                    abstracts.add(name)
         cls.__abstractmethods__ = abstracts
         return cls
 
@@ -86,11 +91,7 @@
     """
 
     def __new__(cls):
-        bad = set()
-        for name in cls.__abstractmethods__:
-            value = getattr(cls, name, None)
-            if getattr(value, "__abstractmethod__", False):
-                bad.add(name)
+        bad = cls.__abstractmethods__
         if bad:
             raise AbstractInstantiationError(bad)
         return super(Abstract, cls).__new__(cls)
@@ -114,7 +115,7 @@
 
     @abstractmethod
     def __iter__(self):
-        return Iterator()
+        return _EmptyIterator()
 
 
 class Iterator(Iterable):
@@ -129,30 +130,38 @@
         return self
 
 
-class Sizeable(Abstract):
+class _EmptyIterator(Iterator):
 
-    @abstractmethod
-    def __len__(self):
-        return 0
+    """Implementation detail used by Iterable.__iter__()."""
 
+    def next(self):
+        # This will call Iterator.next() and hence will raise StopIteration.
+        return super(_EmptyIterator, self).next()
+        # Or: return Iterator.next(self)
+        # Or: raise StopIteration
 
-### SETS ###
 
+class Finite(Abstract):
 
-class BasicSet(Abstract):
+    @abstractmethod
+    def __len__(self):
+        return 0
 
-    # XXX Alternative name: Container? Oracle (as in Delphi's Oracle)?
+class Container(Abstract):
 
-    """A basic set has __contains__() and that's it."""
+    """A container has a __contains__() method."""
 
     @abstractmethod
     def __contains__(self, elem):
         return False
 
 
-class IterableSet(BasicSet, Iterable):
+### SETS ###
+
+
+class BasicSet(Container, Iterable):
 
-    """An iterable set is a basic set that is also iterable.
+    """A basic set is an iterable container.
 
     It may not have a length though; it may be infinite!
 
@@ -161,9 +170,9 @@
     """
 
 
-class SizeableSet(IterableSet, Sizeable):
+class Set(Container, Iterable, Finite):
 
-    """A sizeable set is an iterable set that has a finite, known size.
+    """A plain set is a finite, iterable container.
 
     This enables a generic implementation of equality and ordering based
     on set inclusion.
@@ -175,7 +184,7 @@
     """
 
     def __le__(self, other):
-        if not isinstance(other, SizeableSet):
+        if not isinstance(other, Set):
             return NotImplemented
         if len(self) > len(other):
             return False
@@ -185,12 +194,12 @@
         return True
 
     def __lt__(self, other):
-        if not isinstance(other, SizeableSet):
+        if not isinstance(other, Set):
             return NotImplemented
         return len(self) < len(other) and self.__le__(other)
 
     def __eq__(self, other):
-        if not isinstance(other, SizeableSet):
+        if not isinstance(other, Set):
             return NotImplemented
         return len(self) == len(other) and self.__le__(other)
 
@@ -198,7 +207,7 @@
 
     # XXX The following implementations of &, |, ^, - return frozen sets
     # because we have to pick a concrete type.  They are allowed to
-    # return any subclass of SizeableSet (but SizeableSet is not a
+    # return any subclass of Set (but Set is not a
     # concrete implementation).
 
     def __and__(self, other):
@@ -222,7 +231,7 @@
         return frozenset(new)
 
 
-class HashableSet(SizeableSet, Hashable):
+class HashableSet(Set, Hashable):
 
     def __hash__(self):
         """The hash value must match __eq__.
@@ -231,6 +240,8 @@
         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.
         """
         h = 0
         for elem in self:
@@ -238,16 +249,14 @@
         return h
 
 
-# class set(SizeableSet)
+# class set(Set)
 # class frozenset(HashableSet)
 
 
 ### MAPPINGS ###
 
 
-class BasicMapping(Abstract):
-
-    # XXX derive from (BasicSet)?
+class BasicMapping(Container):
 
     """A basic mapping has __getitem__(), __contains__() and get().
 
@@ -295,7 +304,7 @@
         self._mapping = mapping
 
 
-class KeysView(_MappingView, BasicSet):
+class KeysView(_MappingView, Container):
 
     def __iter__(self):
         for key in self._mapping:
@@ -305,7 +314,7 @@
         return key in self._mapping
 
 
-class ItemsView(_MappingView, BasicSet):
+class ItemsView(_MappingView, Container):
 
     def __iter__(self):
         for key in self._mapping:
@@ -325,26 +334,26 @@
 
 class ValuesView(_MappingView):
 
-    # Note: does not derive from BasicSet, and does not implement __contains__!
+    # Note: does not derive from Container, does not implement __contains__!
 
     def __iter__(self):
         for key in self._mapping:
             yield self._mapping[key]
 
 
-class SizeableMapping(IterableMapping, Sizeable):
+class FiniteMapping(IterableMapping, Finite):
 
     def keys(self):
-        return SizeableKeysView(self)
+        return FiniteKeysView(self)
 
     def items(self):
-        return SizeableItemsView(self)
+        return FiniteItemsView(self)
 
     def values(self):
-        return SizeableValuesView(self)
+        return FiniteValuesView(self)
 
     def __eq__(self, other):
-        if not isinstance(other, SizeableMapping):
+        if not isinstance(other, FiniteMapping):
             return NotImplemented
         if len(other) != len(self):
             return False
@@ -360,24 +369,24 @@
         return True
 
 
-class _SizeableMappingView(_MappingView, Sizeable):
+class _FiniteMappingView(_MappingView, Finite):
 
     def __len__(self):
         return len(self._mapping)
 
 
-class SizeableKeysView(_SizeableMappingView, KeysView, SizeableSet):
+class FiniteKeysView(_FiniteMappingView, KeysView, Set):
     pass
 
 
-class SizeableItemsView(_SizeableMappingView, ItemsView, SizeableSet):
+class FiniteItemsView(_FiniteMappingView, ItemsView, Set):
     pass
 
 
-class SizeableValuesView(_SizeableMappingView, ValuesView):
+class FiniteValuesView(_FiniteMappingView, ValuesView):
 
     def __eq__(self, other):
-        if not (isinstance(other, Sizeable) and isinstance(other, Iterable)):
+        if not (isinstance(other, Finite) and isinstance(other, Iterable)):
             return NotImplemented
         if len(self) != len(other):
             return False
@@ -453,10 +462,10 @@
             stop = size
 
     return start, stop, step
-    
 
 
-class Sequence(Sizeable, Iterable):
+
+class Sequence(Finite, Iterable):
 
     """A minimal sequence.
 
@@ -591,10 +600,10 @@
         return len(self.adaptee)
 
 
-class AdaptToMapping(SizeableMapping):
+class AdaptToMapping(FiniteMapping):
 
     def __new__(cls, adaptee):
-        self = SizeableMapping.__new__(cls)
+        self = FiniteMapping.__new__(cls)
         self.adaptee = adaptee
         return self
 
@@ -608,10 +617,10 @@
         return iter(self.adaptee)
 
 
-class AdaptToSet(SizeableSet):
+class AdaptToSet(Set):
 
     def __new__(cls, adaptee):
-        self = SizeableSet.__new__(cls)
+        self = Set.__new__(cls)
         self.adaptee = adaptee
         return self
 


More information about the Python-checkins mailing list