[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