Search code examples
pythonsubclassingduck-typingisinstanceabstract-base-class

issubclass of abstract base class Sequence


This list shows what methods you need to implement for your class to be "regarded" as Sequence: __getitem__, __len__, __contains__, __iter__, __reversed__, index, and count. So why does this minimal implementation does not work, i.e. why issubclass(S, Sequence) is False?

from collections import *


class S(object):
    def __getitem__(self, item):
        raise IndexError

    def __len__(self):
        return 0

    def __contains__(self, item):
        return False

    def __iter__(self):
        return iter(())

    def __reversed__(self):
        return self

    def index(self, item):
        raise IndexError

    def count(self, item):
        return 0


issubclass(S, Iterable)   # True  :-)
issubclass(S, Sized)      # True  :-)
issubclass(S, Container)  # True  :-)
issubclass(S, Sequence)   # False :-(

Is there an additional method I need to implement that I overlooked? Did I misunderstand abstract base classes? Subclassing Sequence makes issubclass return True of course, but that kinda defeats the idea behind abc, doesn't it?


Solution

  • Use the source, Luke!

    Sequence does not implement its own __subclasshook__, and all the implementations of __subclasshook__ from the parents of Sequence have checks like this:

    class Iterable:
        ...
    
        @classmethod
        def __subclasshook__(cls, C):
            if cls is Iterable:  # <<<<
                if _hasattr(C, "__iter__"):
                    return True
            return NotImplemented
    

    You can however explicitly register() your class as a Sequence:

    Sequence.register(S)
    

    As for the reason why Sequence does not implement __subclasshook__, see issue 16728 (which title was initially "collections.abc.Sequence shoud provide __subclasshook__"). The issue can be summarized by saying that a sequence can be many things, depending on the needs of who uses it:

    Many algorithms that require a sequence only need __len__ and __getitem__. [...] collections.abc.Sequence is a much richer interface.