There is a precedent for declaring that a method isn't implemented: __hash__. The convention is to set it to None in the subclass that explicitly doesn't want to implement it. The __subclasshook__ in collections.Hashable checks for this. The pattern is also used for __await__.

On Sat, Dec 26, 2015 at 1:09 PM, Andrew Barnert via Python-ideas <python-ideas@python.org> wrote:
On Dec 26, 2015, at 04:00, Serhiy Storchaka <storchaka@gmail.com> wrote:
>
>> On 07.11.15 00:11, Amir Rachum wrote:
>> I am suggesting the addition of a collections abstract base class called
>> "Ordered". Its meaning is that a collection's iteration order is part of
>> its API. The bulk of this mail describes a use case for this. The reason
>> I believe that such abstract base class is required is that there is no
>> way to test this behavior in a given class. An ordered collection has
>> the exact same interface as an unordered collection (e.g, dict and
>> OrderedDict), other than a _promise_ of the API that the order in which
>> this collection will be iterated has some sort of meaning (In
>> OrderedDict, it is the order in which keys were added to it.)
>>
>> As examples, set, frozenset, dict and defaultdict should *not* be
>> considered as ordered. list, OrderedDict, deque and tuple should be
>> considered ordered.
>
> Actually we already have such abstract class. It's typing.Reversible.

But surely an infinite list, for example, is ordered but not reversible.

Also, typing types aren't abstract base classes--one is for static type checking, the other for runtime tests. Of course they're closely related, but if they were the same thing, we wouldn't need a separate module for typing in the first place.

Of course there's nothing stopping us from adding collections.abc.Reversible, but that still doesn't solve the problem that not all ordered things are reversible. (I still don't think Ordered is necessary--but if it is, I don't think Reversible being kind of close helps, any more than Sequence and Iterable both being kind of close helps.)

> Unfortunately the test returns False for tuple, str, bytes, bytearray, and array:

It's defined (and implemented) as testing for the presence of __reversed__. But the reverse function works on types that don't implement __reversed__ if they implement the old-style sequence protocol, which can't be tested structurally.

Iterable is defined similarly, but it's a supertype of Sequence, and all of those builtin types get registered explicitly with Sequence (as some third-party types do), so they're all Iterable too.

The obvious fix is to make Reversible a subtype of Iterable, and Sequence a subtype of Reversible instead of Iterable. That would fix tuple, str, and all the other types that are registered explicitly with Sequence or MutableSequence.

This still doesn't cover OrderedDict and friends, but they could be explicitly registered with Reversible.

I think for any solution to work with static typing, you'd also need to change the hierarchy in typing to parallel the new hierarchy in collections.abc, and change typing.Reversible to use collections.abc.Reversible as its "extra".

One last thing: issue 25864, about all mappings except dict and its subclasses accidentally (and incorrectly) implementing the old-style sequence protocol well enough that when you call reverse on them, you successfully get an unusable iterator, instead of getting a TypeError. The only obvious fix is to add a __reversed__ that raises. But, as you pointed out there, that makes the problem with typing.Reversible (and any collections.abc.Reversible) worse. Currently, by being overly strict, Reversible happens to fail on Mapping subclasses, for the same reason it fails on things that actually _are_ properly reversible. I'm not sure what the solution is there. Fixing both Reversible and Mapping will accidentally make all
Mappings statically pass as Reversible, which we definitely don't want. Maybe we need a way to explicitly mark (for type checking) that a method isn't implemented, or to explicitly "unregister" from an ABC and/or typing type that takes precedence over structural checks?
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/



--
--Guido van Rossum (python.org/~guido)