Dennis,
Thanks for the (very complete) explanation. I induced to err because of the
following confusing facts:
```
from collections.abc import Mapping, Sequence
import sys
if sys.version_info <= (2, 7):
assert '__reversed__' not in dir(Mapping)
elif sys.version_info >= (3, 7):
assert not isinstance(Mapping, Sequence)
assert '__reversed__' in dir(Mapping)
assert list(reversed(dict.fromkeys('abc'))) == ['c', 'b', 'a']
# + no mention of Mapping.__reversed__ in the docs
```
Indeed, I didn't look at the code. Thanks for that.
On Thu, Apr 23, 2020 at 5:28 PM Dennis Sweeney <report@bugs.python.org>
wrote:
>
> Dennis Sweeney <sweeney.dennis650@gmail.com> added the comment:
>
> > `Mapping.__reversed__` exists
>
> While ``'__reversed__' in dir(Mapping)`` is true, that unfortunately does
> not mean that it is a real callable method:
>
>
> from collections.abc import Mapping
> class Map(Mapping):
> def __getitem__(self, x):
> if x == 42:
> return 17
> raise KeyError
> def __len__(self, x):
> return 1
> def __iter__(self):
> yield 42
>
> >>> m = Map()
> >>> reversed(m)
> Traceback (most recent call last):
> ...
> TypeError: 'Map' object is not reversible
>
> In the code for Mapping, ``__reversed__`` is explicitly defined as None
> [1] so that calling ``reversed(custom_mapping)`` doesn't accidentally fall
> back on the sequence protocol, which would mean starting at
> len(custom_mapping)-1 and calling __getitem__ on each index [2], which is
> certainly not desirable for arbitrary mappings.
>
> I don't think there is a reasonable way, given arbitrary implementations
> of __len__, __iter__, and __getitem__, to have a mixin reversed iterator.
> If someone wants their mapping to have a __reversed__ method, they should
> define it themselves.
>
> [1]
> https://github.com/python/cpython/blob/master/Lib/_collections_abc.py#L707
> [2]
> https://docs.python.org/3/reference/datamodel.html?highlight=__reversed__#object.__reversed__
>
> ----------
> nosy: +Dennis Sweeney
>
> _______________________________________
> Python tracker <report@bugs.python.org>
> <https://bugs.python.org/issue40374>
> _______________________________________
>
|