
On Fri, 8 Jan 2021 at 22:25, Greg Ewing <greg.ewing@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