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

guido.van.rossum python-checkins at python.org
Fri Apr 20 23:24:23 CEST 2007


Author: guido.van.rossum
Date: Fri Apr 20 23:24:20 2007
New Revision: 54894

Modified:
   sandbox/trunk/abc/abc.py
Log:
Use Sized instead of Finite.
Implement the instantiation check entirely in the metaclass
(though still too expensive, due to extensive super usage).


Modified: sandbox/trunk/abc/abc.py
==============================================================================
--- sandbox/trunk/abc/abc.py	(original)
+++ sandbox/trunk/abc/abc.py	Fri Apr 20 23:24:20 2007
@@ -64,9 +64,39 @@
                 if getattr(value, "__isabstractmethod__", False):
                     abstracts.add(name)
         cls.__abstractmethods__ = abstracts
+        if abstracts:
+            _disable_construction(cls)
         return cls
 
 
+def _disable_construction(cls):
+    """Helper to ensure that a class cannot be instantiated.
+
+    This is done by planting a __new__ method that raises an exception
+    if its first argument is the cls argument to this function.
+    """
+    # XXX This still may be too much overhead; imagine a concrete class
+    # deriving from a stack of ABCs, it will bounce off each ABC's
+    # __new__ method
+    # XXX Should we store the shadowed function on the class?
+    # XXX Is it a good idea to name the new function __new__?
+    dct = cls.__dict__
+    shadowed_new = dct.get("__new__")
+    if not shadowed_new:
+        @staticmethod
+        def __new__(c, *a, **k):
+            if c is cls:
+                raise AbstractInstantiationError(cls.__abstractmethods__)
+            return super(cls, c).__new__(c, *a, **k)
+    else:
+        @staticmethod
+        def __new__(c, *a, **k):
+            if c is cls:
+                raise AbstractInstantiationError(cls.__abstractmethods__)
+            return shadowed_new(c, *a, **k)
+    cls.__new__ = __new__
+
+
 class AbstractInstantiationError(TypeError):
 
     """Exception raised when an abstract class is instantiated."""
@@ -90,12 +120,6 @@
     This implicitly sets the metaclass to AbstractClass.
     """
 
-    def __new__(cls):
-        bad = cls.__abstractmethods__
-        if bad:
-            raise AbstractInstantiationError(bad)
-        return super(Abstract, cls).__new__(cls)
-
 
 ### BASICS ###
 
@@ -141,7 +165,7 @@
         # Or: raise StopIteration
 
 
-class Finite(Abstract):
+class Sized(Abstract):
 
     @abstractmethod
     def __len__(self):
@@ -170,7 +194,7 @@
     """
 
 
-class Set(Container, Iterable, Finite):
+class Set(Container, Iterable, Sized):
 
     """A plain set is a finite, iterable container.
 
@@ -341,19 +365,19 @@
             yield self._mapping[key]
 
 
-class FiniteMapping(IterableMapping, Finite):
+class SizedMapping(IterableMapping, Sized):
 
     def keys(self):
-        return FiniteKeysView(self)
+        return SizedKeysView(self)
 
     def items(self):
-        return FiniteItemsView(self)
+        return SizedItemsView(self)
 
     def values(self):
-        return FiniteValuesView(self)
+        return SizedValuesView(self)
 
     def __eq__(self, other):
-        if not isinstance(other, FiniteMapping):
+        if not isinstance(other, SizedMapping):
             return NotImplemented
         if len(other) != len(self):
             return False
@@ -369,24 +393,24 @@
         return True
 
 
-class _FiniteMappingView(_MappingView, Finite):
+class _SizedMappingView(_MappingView, Sized):
 
     def __len__(self):
         return len(self._mapping)
 
 
-class FiniteKeysView(_FiniteMappingView, KeysView, Set):
+class SizedKeysView(_SizedMappingView, KeysView, Set):
     pass
 
 
-class FiniteItemsView(_FiniteMappingView, ItemsView, Set):
+class SizedItemsView(_SizedMappingView, ItemsView, Set):
     pass
 
 
-class FiniteValuesView(_FiniteMappingView, ValuesView):
+class SizedValuesView(_SizedMappingView, ValuesView):
 
     def __eq__(self, other):
-        if not (isinstance(other, Finite) and isinstance(other, Iterable)):
+        if not (isinstance(other, Sized) and isinstance(other, Iterable)):
             return NotImplemented
         if len(self) != len(other):
             return False
@@ -465,7 +489,7 @@
 
 
 
-class Sequence(Finite, Iterable):
+class Sequence(Sized, Iterable):
 
     """A minimal sequence.
 
@@ -600,10 +624,10 @@
         return len(self.adaptee)
 
 
-class AdaptToMapping(FiniteMapping):
+class AdaptToMapping(SizedMapping):
 
     def __new__(cls, adaptee):
-        self = FiniteMapping.__new__(cls)
+        self = SizedMapping.__new__(cls)
         self.adaptee = adaptee
         return self
 


More information about the Python-checkins mailing list