Hi Ilya,

I'm not sure that this mailing list (Python-Dev) is the right place for 
this discussion, I think that Python-Ideas (CCed) is the correct place.

For the benefit of Python-Ideas, I have left your entire post below, to 
establish context.

[Ilya]
> I needed reversed(enumerate(x: list)) in my code, and have discovered 
> that it wound't work. This is disappointing because operation is well 
> defined.

It isn't really well-defined, since enumerate can operate on infinite 
iterators, and you cannot reverse an infinite stream. Consider:

    def values():
        while True:
            yield random.random()

    a, b = reversed(enumerate(values())

What should the first pair of (a, b) be?

However, having said that, I think that your idea is not unreasonable. 
`enumerate(it)` in the most general case isn't reversable, but if `it` 
is reversable and sized, there's no reason why `enumerate(it)` shouldn't 
be too.

My personal opinion is that this is a fairly obvious and straightforward 
enhancement, one which (hopefully!) shouldn't require much, if any, 
debate. I don't think we need a new class for this, I think enhancing 
enumerate to be reversable if its underlying iterator is reversable 
makes good sense.

But if you can show some concrete use-cases, especially one or two from 
the standard library, that would help your case. Or some other languages 
which offer this functionality as standard.

On the other hand, I think that there is a fairly lightweight work 
around. Define a helper function:

    def countdown(n):
        while True:
            yield n
            n -= 1

then call it like this:

    # reversed(enumerate(seq))
    zip(countdown(len(seq)-1), reversed(seq)))

So it isn't terribly hard to work around this. But I agree that it would 
be nice if enumerate encapsulated this for the caller.

One potentially serious question: what should `enumerate.__reversed__` 
do when given a starting value?

    reversed(enumerate('abc', 1))

Should that yield...?

    # treat the start value as a start value
    (1, 'c'), (0, 'b'), (-1, 'a')

    # treat the start value as an end value
    (3, 'c'), (2, 'b'), (1, 'a')

Something else?

My preference would be to treat the starting value as an ending value.


Steven


On Wed, Apr 01, 2020 at 08:45:34PM +0200, Ilya Kamenshchikov wrote:
> Hi,
> 
> I needed reversed(enumerate(x: list)) in my code, and have discovered that
> it wound't work. This is disappointing because operation is well defined.
> It is also well defined for str type, range, and - in principle, but not
> yet in practice - on dictionary iterators - keys(), values(), items() as
> dictionaries are ordered now.
> It would also be well defined on any user type implementing __iter__,
> __len__, __reversed__ - think numpy arrays, some pandas dataframes, tensors.
> 
> That's plenty of usecases, therefore I guess it would be quite useful to
> avoid hacky / inefficient solutions like described here:
> https://code.activestate.com/lists/python-list/706205/.
> 
> If deemed useful, I would be interested in implementing this, maybe
> together with __reversed__ on dict keys, values, items.
> 
> Best Regards,
> --
> Ilya Kamen
> 
> -----------
> p.s.
> 
> *Sketch* of what I am proposing:
> 
> class reversible_enumerate:
> 
>     def __init__(self, iterable):
>         self.iterable = iterable
>         self.ctr = 0
> 
>     def __iter__(self):
>         for e in self.iterable:
>             yield self.ctr, e
>             self.ctr += 1
> 
>     def __reversed__(self):
>         try:
>             ri = reversed(self.iterable)
>         except Exception as e:
>             raise Exception(
>                 "enumerate can only be reversed if iterable to
> enumerate can be reversed and has defined length."
>             ) from e
> 
>         try:
>             l = len(self.iterable)
>         except Exception as e:
>             raise Exception(
>                 "enumerate can only be reversed if iterable to
> enumerate can be reversed and has defined length."
>             ) from e
> 
>         indexes = range(l-1, -1, -1)
>         for i, e in zip(indexes, ri):
>             yield i, e
> 
> for i, c in reversed(reversible_enumerate("Hello World")):
>     print(i, c)
> 
> for i, c in reversed(reversible_enumerate([11, 22, 33])):
> 
>     print(i, c)

> _______________________________________________
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at 
> https://mail.python.org/archives/list/python-dev@python.org/message/NDDKDUDHE3J7SR7IPO3QXCVFSGE4BAV4/
> Code of Conduct: http://python.org/psf/codeofconduct/
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/LCZS4UUH7UEQN6NTW76UY23RCEITXQKB/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to