On Fri, 8 Jan 2021 at 22:25, Greg Ewing <greg.ew...@canterbury.ac.nz> wrote:
>
> On 9/01/21 10:19 am, Ram Rachum wrote:
> > In short, I want `reversed(itertools.chain(x, y, z))` that behaves like
> > `itertools.chain(map(reversed, (z, y, x)))`.
>
> I think you mean `itertools.chain(*map(reversed, (z, y, x)))`
>
> You can get this with
>
>      itertools.chain(*map(reversed, reversed(t)))
>
> Making `reversed(itertools.chain(x, y, z))` do this would be a
> backwards incompatible change.
>
> Also it's hard to see how it could be made to work, because the
> argument to reversed() necessarily has to be a sequence, not an
> iterator.

The argument to reversed either needs to be a sequence with __len__
and __getitem__ or an object with a __reversed__ method that returns
an iterator. The arguments to chain have to be iterables. Every
sequence is an iterable so there is a significant intersection between
the possible inputs to chain and reversed. Also some non-sequences
such as dict can work with reversed.

You say it's hard to see how it could be made to work but you've shown
precisely how it can already be done above:

     reversed(chain(*args))   ==   chain(*map(reversed, reversed(args)))

We can try that out and it certainly seems to work:

    >>> from itertools import chain
    >>> args = [[1, 2], [3, 4]]
    >>> list(chain(*args))
    [1, 2, 3, 4]
    >>> list(chain(*map(reversed, reversed(args))))
    [4, 3, 2, 1]

This wouldn't work with chain.from_iterable without preconsuming the
top-level iterable but in the case of chain the iterables are already
in a *args tuple so flipping that order is always possible in a lazy
way. That means the operation works fine if each arg in args is
reversible. Otherwise if any arg is not reversible then it should give
a TypeError just like reversed(set()) does except the error would
potentially be delayed if some of the args are reversible and some are
not.

I haven't ever wanted to reverse a chain but I have wanted to be able
to reverse an enumerate many times:

    >>> reversed(enumerate([1, 2, 3]))
    ...
    TypeError

The alternative zip(range(len(obj)-1, -1, -1), reversed(obj)) is
fairly cryptic in comparison as well as probably being less efficient.
There could be a __reversed__ method for enumerate with the same
caveat as for chain: if the underlying object is not reversible then
you get a TypeError. Otherwise reversed(enumerate(seq)) works fine for
any sequence seq.

The thornier issue is how to handle reversed if the chain/enumerate
iterator has already been partially consumed. If it's possible just to
give an error in that case then reversed could still be useful in the
common case.

--
Oscar
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/5LH3EL3QF4WN62BE5X2RTNWT3GRHANAA/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to