[Python-3000-checkins] r55847 - in python/branches/p3yk/Lib: abc.py collections.py test/test_collections.py
guido.van.rossum
python-3000-checkins at python.org
Sat Jun 9 17:28:07 CEST 2007
Author: guido.van.rossum
Date: Sat Jun 9 17:28:06 2007
New Revision: 55847
Modified:
python/branches/p3yk/Lib/abc.py
python/branches/p3yk/Lib/collections.py
python/branches/p3yk/Lib/test/test_collections.py
Log:
Different way to do one trick ponies, allowing registration (per PEP strawman).
Modified: python/branches/p3yk/Lib/abc.py
==============================================================================
--- python/branches/p3yk/Lib/abc.py (original)
+++ python/branches/p3yk/Lib/abc.py Sat Jun 9 17:28:06 2007
@@ -46,6 +46,17 @@
(cls.__name__, ", ".join(sorted(am))))
return super(_Abstract, cls).__new__(cls, *args, **kwds)
+ @classmethod
+ def __subclasshook__(cls, subclass):
+ """Abstract classes can override this to customize issubclass().
+
+ This is invoked early on by __subclasscheck__() below. It
+ should return True, False or NotImplemented. If it returns
+ NotImplemented, the normal algorithm is used. Otherwise, it
+ overrides the normal algorithm (and the outcome is cached).
+ """
+ return NotImplemented
+
def _fix_bases(bases):
"""Helper method that inserts _Abstract in the bases if needed."""
@@ -144,6 +155,15 @@
cls.__negative_cache = set()
elif subclass in cls.__negative_cache:
return False
+ # Check the subclass hook
+ ok = cls.__subclasshook__(subclass)
+ if ok is not NotImplemented:
+ assert isinstance(ok, bool)
+ if ok:
+ cls.__cache.add(subclass)
+ else:
+ cls.__negative_cache.add(subclass)
+ return ok
# Check if it's a direct subclass
if cls in subclass.__mro__:
cls.__cache.add(subclass)
Modified: python/branches/p3yk/Lib/collections.py
==============================================================================
--- python/branches/p3yk/Lib/collections.py (original)
+++ python/branches/p3yk/Lib/collections.py Sat Jun 9 17:28:06 2007
@@ -51,15 +51,11 @@
class _OneTrickPony(metaclass=_ABCMeta):
- @classmethod
- def __instancecheck__(cls, x):
- return issubclass(x.__class__, cls)
-
- @classmethod
- def register(cls, C):
- raise TypeError("class %s doesn't allow registration of subclasses" %
- cls.__name__)
+ """Helper class for Hashable and friends."""
+ @_abstractmethod
+ def __subclasshook__(self, subclass):
+ return NotImplemented
class Hashable(_OneTrickPony):
@@ -68,11 +64,13 @@
return 0
@classmethod
- def __subclasscheck__(cls, C):
+ def __subclasshook__(cls, C):
for B in C.__mro__:
if "__hash__" in B.__dict__:
- return B.__dict__["__hash__"] is not None
- return False
+ if B.__dict__["__hash__"]:
+ return True
+ break
+ return NotImplemented
class Iterable(_OneTrickPony):
@@ -83,9 +81,11 @@
yield None
@classmethod
- def __subclasscheck__(cls, C):
- return any("__iter__" in B.__dict__ or "__getitem__" in B.__dict__
- for B in C.__mro__)
+ def __subclasshook__(cls, C):
+ if any("__iter__" in B.__dict__ or "__getitem__" in B.__dict__
+ for B in C.__mro__):
+ return True
+ return NotImplemented
class Iterator(_OneTrickPony):
@@ -98,8 +98,10 @@
return self
@classmethod
- def __subclasscheck__(cls, C):
- return any("__next__" in B.__dict__ for B in C.__mro__)
+ def __subclasshook__(cls, C):
+ if any("__next__" in B.__dict__ for B in C.__mro__):
+ return True
+ return NotImplemented
class Sized(_OneTrickPony):
@@ -109,8 +111,10 @@
return 0
@classmethod
- def __subclasscheck__(cls, C):
- return any("__len__" in B.__dict__ for B in C.__mro__)
+ def __subclasshook__(cls, C):
+ if any("__len__" in B.__dict__ for B in C.__mro__):
+ return True
+ return NotImplemented
class Container(_OneTrickPony):
@@ -120,7 +124,7 @@
return False
@classmethod
- def __subclasscheck__(cls, C):
+ def __subclasshook__(cls, C):
return any("__contains__" in B.__dict__ for B in C.__mro__)
Modified: python/branches/p3yk/Lib/test/test_collections.py
==============================================================================
--- python/branches/p3yk/Lib/test/test_collections.py (original)
+++ python/branches/p3yk/Lib/test/test_collections.py Sat Jun 9 17:28:06 2007
@@ -79,11 +79,12 @@
def __hash__(self):
return super(H, self).__hash__()
self.assertEqual(hash(H()), 0)
- # Check registration is disabled
+ # Check registration
class C:
- def __hash__(self):
- return 0
- self.assertRaises(TypeError, Hashable.register, C)
+ __hash__ = None
+ self.failIf(issubclass(C, Hashable))
+ Hashable.register(C)
+ self.failUnless(issubclass(C, Hashable))
def test_Iterable(self):
non_samples = [None, 42, 3.14, 1j]
More information about the Python-3000-checkins
mailing list