This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: collections.abc docs table: Mapping missing __reversed__
Type: Stage: resolved
Components: Documentation Versions: Python 3.8
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: docs@python Nosy List: Dennis Sweeney, Thor Whalen, Thor Whalen2, docs@python, rhettinger, stutzbach
Priority: normal Keywords:

Created on 2020-04-23 16:02 by Thor Whalen2, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 19680 closed Thor Whalen2, 2020-04-23 16:02
Messages (3)
msg367127 - (view) Author: Thor Whalen (Thor Whalen2) Date: 2020-04-23 16:02
`Mapping.__reversed__` exists, but is not listed in the table: https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes

https://github.com/python/cpython/blob/master/Doc/library/collections.abc.rst
msg367147 - (view) Author: Dennis Sweeney (Dennis Sweeney) * (Python committer) Date: 2020-04-23 21:27
> `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__
msg367206 - (view) Author: Thor Whalen (Thor Whalen) * Date: 2020-04-24 17:34
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>
> _______________________________________
>
History
Date User Action Args
2022-04-11 14:59:29adminsetgithub: 84554
2020-04-24 17:58:39rhettingersetstatus: open -> closed
resolution: not a bug
stage: resolved
2020-04-24 17:34:13Thor Whalensetnosy: + Thor Whalen
messages: + msg367206
2020-04-23 21:27:58Dennis Sweeneysetnosy: + Dennis Sweeney
messages: + msg367147
2020-04-23 16:02:41Thor Whalen2create