classification
Title: collections.abc.Sequence cannot be used to test whether a class provides a particular interface (doc issue)
Type: Stage:
Components: Documentation, Library (Lib) Versions: Python 3.8, Python 3.7, Python 3.6
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: docs@python Nosy List: docs@python, hroncok, levkivskyi, p-ganssle, rhettinger, serhiy.storchaka, stutzbach, vstinner
Priority: normal Keywords:

Created on 2018-11-08 14:41 by hroncok, last changed 2018-11-12 00:09 by vstinner.

Messages (4)
msg329475 - (view) Author: Miro Hrončok (hroncok) * Date: 2018-11-08 14:41
The collections.abc — Abstract Base Classes for Containers documentation says:

> This module provides abstract base classes that can be used to test whether a class provides a particular interface; for example, whether it is hashable or whether it is a mapping.

https://docs.python.org/3/library/collections.abc.html

However this is not true for Sequence.

When I implement a class that provides a particular interface (defined in the Collections Abstract Base Classes table in that very page), I cannot check whether it implements a Sequence.

See an example:

    from collections import abc

    class Box:
        def __init__(self, wrapped):
            self._w = wrapped

        def __len__(self):
            return len(self._w)

        def __iter__(self):
            yield from self._w

        def __getitem__(self, i):
            return self._w[i]

        def __reversed__(self):
            yield from reversed(self._w)

        def __contains__(self, i):
            return i in self._w

        def index(self, value, start=0, stop=None):
            return self._w.index(value, start, stop)

        def count(self, value):
            return self._w.count(value)


    b = Box([1, 2, 3])

    for t in 'Sized', 'Iterable', 'Reversible', 'Container', 'Collection', 'Sequence':
        print(f'{t}: {isinstance(b, getattr(abc, t))}')


My class is Reversible.
My class is a Collection (as it is a Sized Iterable Container).
It implements __getitem__, __len__, __contains__, __iter__, __reversed__, index, and count.

Yet my class instance is not an instance of Sequence.

I suppose this behavior might be intentional, as discussed in issue16728 - or it might as well not be.

The main concern was that dict also provides these methods, but is not considered a Sequence,
however dict does not provide index() or count().

Regardless whether this is right or wrong behavior, as documented this should be a Sequence.

See also https://stackoverflow.com/questions/34927949/issubclass-of-abstract-base-class-sequence


As I see it, either:

    collections.abc.Sequence needs a __subclasshook__ so it can be used as the documentation implies.

Or:

    the documentation should not say that "abstract base classes (from abc module) can be used to test whether a class provides a particular interface" if it doesn't generally apply


Or:

    the Sequence documentation should say: "this particular abstract base class cannot be used to test whether a class provides a particular interface because reasons" (yet I don't really get those reasons)
msg329476 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2018-11-08 15:22
Yeah, the docs need to be clarified.
msg329477 - (view) Author: Miro Hrončok (hroncok) * Date: 2018-11-08 15:33
I fail to understand what abc classes can be used to test whether a class provides a particular interface, and what abc classes cannot be used that way. What is the difference between those abc classes and why are all those abc classes listed together when they behave differently?
msg329610 - (view) Author: Ivan Levkivskyi (levkivskyi) * (Python committer) Date: 2018-11-10 14:34
The separation may look arbitrary, but the idea is quite simple. Only those classes with few methods support structural checks. Those classes have few independent abstract methods (or even just one method), while in classes with large APIs like `Sequence`, the methods are not logically independent, so you can't say a class is 100% a `Sequence` even if types/signatures of all methods are correct, because e.g. `__contains__()` and `index()` should behave in agreement with `__getitem__()`.

We might explicitly document which ABCs support structural checks, and which require explicit subclassing. Also we might clarify what "abstract methods" and "mixin methods" mean in the table at the top. In the case of `Sequence` one can just implement two abstract methods and the other will behave in a "coordinated way". Then, simple purely abstract classes (called "One-trick ponies" in the source code) support structural checks.

> The collections.abc — Abstract Base Classes for Containers documentation says:

>> This module provides abstract base classes that can be used to test whether a class provides a particular interface; for example, whether it is hashable or whether it is a mapping.

Btw, Mapping also doesn't support structural checks, so the docs are quite outdated.
History
Date User Action Args
2018-11-12 00:09:26vstinnersettitle: collections.abc.Sequence cannot be used to test whether a class provides a particular interface -> collections.abc.Sequence cannot be used to test whether a class provides a particular interface (doc issue)
2018-11-10 14:34:52levkivskyisetnosy: + levkivskyi
messages: + msg329610
2018-11-08 17:11:42serhiy.storchakasetnosy: + stutzbach
2018-11-08 16:44:03p-gansslesetnosy: + p-ganssle
2018-11-08 15:33:54hroncoksetmessages: + msg329477
2018-11-08 15:23:00gvanrossumsetnosy: - gvanrossum
2018-11-08 15:22:55gvanrossumsetmessages: + msg329476
2018-11-08 15:18:35vstinnersetnosy: + gvanrossum, rhettinger, serhiy.storchaka
2018-11-08 14:41:26hroncokcreate