[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