[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