6

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?

Kijewski
  • 25,517
  • 12
  • 101
  • 143
  • 1
    Just because a class implements the sequence interface does not make it a subclass of Sequence. – Daniel Roseman Jan 21 '16 at 15:42
  • 2
    I think OP already knows that. See [abc](https://docs.python.org/2/library/abc.html#module-abc). – Vlad Jan 21 '16 at 15:43
  • To me there seems to be a disconnect here between what's colloquially considered a sequence in Python (`__len__` and `__getitem__` with ints) and what's formally considered a Sequence by the language (per `insinstance`). As it stands, you cannot look at an object's methods and decide whether it is formally considered a sequence, which is weird to me. – timgeb Apr 14 '18 at 15:39

1 Answers1

12

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.

Andrea Corbellini
  • 17,339
  • 3
  • 53
  • 69
  • 1
    In other words collections.Sequence is pointless (/incomplete) unless used as a mixin? – Kijewski Jan 21 '16 at 15:44
  • @Kay: it give you the features of many other abstract base classes: you get an exception if you try to inherit without defining all the required methods, and you can explicit `register()` arbitrary subclasses – Andrea Corbellini Jan 21 '16 at 15:46
  • Hm, seems like an blatant oversight by the Python hackers to my to be honest. Do you know a reason why `Sequence.__subclasshook__` is not implemented? – Kijewski Jan 21 '16 at 15:48
  • @Kay: `__subclasshook__` is a bit pointless. Example: having an attribute `__iter__` does not imply that an instance has correctly implemented an iterable. – Andrea Corbellini Jan 21 '16 at 15:48
  • Thank you! Now I understand the problem. – Kijewski Jan 21 '16 at 15:58