diff -r 8dea55fb20e9 Lib/_collections_abc.py --- a/Lib/_collections_abc.py Sat Aug 23 18:29:02 2014 -0400 +++ b/Lib/_collections_abc.py Mon Aug 25 00:01:48 2014 +0200 @@ -6,7 +6,7 @@ Unit tests are in test_collections. """ -from abc import ABCMeta, abstractmethod +from abc import ABCMeta, abstractmethod, mrohasattr, mrogetattr import sys __all__ = ["Hashable", "Iterable", "Iterator", @@ -64,13 +64,9 @@ @classmethod def __subclasshook__(cls, C): - if cls is Hashable: - for B in C.__mro__: - if "__hash__" in B.__dict__: - if B.__dict__["__hash__"]: - return True - break - return NotImplemented + return cls is Hashable \ + and bool(mrogetattr(C, "__hash__")) \ + or NotImplemented class Iterable(metaclass=ABCMeta): @@ -84,10 +80,9 @@ @classmethod def __subclasshook__(cls, C): - if cls is Iterable: - if any("__iter__" in B.__dict__ for B in C.__mro__): - return True - return NotImplemented + return cls is Iterable \ + and mrohasattr(C, "__iter__") \ + or NotImplemented class Iterator(Iterable): @@ -104,11 +99,9 @@ @classmethod def __subclasshook__(cls, C): - if cls is Iterator: - if (any("__next__" in B.__dict__ for B in C.__mro__) and - any("__iter__" in B.__dict__ for B in C.__mro__)): - return True - return NotImplemented + return cls is Iterator \ + and (mrohasattr(C, "__next__") and mrohasattr(C, "__iter__")) \ + or NotImplemented Iterator.register(bytes_iterator) Iterator.register(bytearray_iterator) @@ -134,10 +127,9 @@ @classmethod def __subclasshook__(cls, C): - if cls is Sized: - if any("__len__" in B.__dict__ for B in C.__mro__): - return True - return NotImplemented + return cls is Sized \ + and mrohasattr(C, "__len__") \ + or NotImplemented class Container(metaclass=ABCMeta): @@ -150,10 +142,9 @@ @classmethod def __subclasshook__(cls, C): - if cls is Container: - if any("__contains__" in B.__dict__ for B in C.__mro__): - return True - return NotImplemented + return cls is Container \ + and mrohasattr(C, "__contains__") \ + or NotImplemented class Callable(metaclass=ABCMeta): @@ -166,10 +157,9 @@ @classmethod def __subclasshook__(cls, C): - if cls is Callable: - if any("__call__" in B.__dict__ for B in C.__mro__): - return True - return NotImplemented + return cls is Callable \ + and mrohasattr(C, "__call__") \ + or NotImplemented ### SETS ### diff -r 8dea55fb20e9 Lib/abc.py --- a/Lib/abc.py Sat Aug 23 18:29:02 2014 -0400 +++ b/Lib/abc.py Mon Aug 25 00:01:48 2014 +0200 @@ -6,6 +6,17 @@ from _weakrefset import WeakSet +def mrohasattr(cls, attr): + "Return wether cls has attr in mro" + return any(attr in B.__dict__ for B in cls.__mro__) + +def mrogetattr(cls, attr, default=NotImplemented): + "Return the first attr of cls found in mro or default (NotImplemented if default not given)" + try: + return next(B.__dict__[attr] for B in cls.__mro__ if attr in B.__dict__) + except StopIteration: + return default + def abstractmethod(funcobj): """A decorator indicating abstract methods.