[Python-ideas] Where did we go wrong with negative stride?

Guido van Rossum guido at python.org
Sun Oct 27 21:44:50 CET 2013


On Sun, Oct 27, 2013 at 11:38 AM, Tim Peters <tim.peters at gmail.com> wrote:

> I may have a different slant on this.


Hardly -- I agree with everything you say here. :-)


> I've found that - by far - the
> most successful way to "teach slices" to newcomers is to invite them
> to view indices as being _between_ sequence elements.
>

Yup.

>
> <position 0> <element> <position 1> <element> <position 2> <element>
> <position 3> ...
>
> Then i:j selects the elements between position i and position j.
>
> >>> "abcde"[2:4]
> 'cd'
>
> But for negative strides this is all screwed up ;-)
>
> >>> "abcde"[4:2:-1]
> 'ed'
>

Right, that's the point of my post.

>
> They're not getting the elements between "positions" 2 and 4 then,
> they're getting the elements between positions 3 and 5.  Why?
> "Because that's how it works" - they have to switch from thinking
> about positions to thinking about array indexing.
>
> So I would prefer that the i:j in s[i:j:k] _always_ specify the
> positions in play:
>
> If i < 0:
>     i += len(s)  # same as now
> if j < 0:
>     j += len(s)  # same as now
> if i >= j:
>     the slice is empty!  # this is different - the sign of k is irrelevant
> else:
>     the slice indices selected will be
>         i, i + abs(k), i + 2*abs(k), ...
>     up to but not including j
>     if k is negative, this index sequence will be taken in reverse order
>
> Then "abcde"[4:2:-1] would be "", while "abcde"[2:4:-1] would be "dc",
> the reverse of "abcde"[2:4].  And s[0:len(s):-1] would be the same as
> reversed(s).
>

Except reversed() returns an iterator. But yes.

This would also make a[i:j:k] == a[i:j][::k].

If I could do it over I would do it this way.

>
> So it's always a semi-open range, inclusive "at the left" and
> exclusive "at the right".  But that's more a detail:  the _point_ is
> to preserve the mental model of selecting the elements "between
> position".  Of course I'd change range() similarly.
>

Which probably would cause more backward incompatibility bugs, since by now
many people have figured out that if you want [4, 3, 2, 1, 0] you have to
write range(4, -1, -1). :-(

>
>
> [Guido]
> > For example,
> >
> > "abcde"[::-1] == "edcba"
> >
> > as you'd expect, but there is no number you can put as the second bound
> to
> > get the same result:
>
> Actually, any integer <= -1-len("abcde") = --6 works.  But, yes,
> that's bizarre ;-)
>

Yup, MRAB pointed this out too.

>
> >...
> > Are we stuck with this forever?
>
> Probably :-(
>

Sadly, I agree. If we wanted to change this in Python 4, we'd probably have
to start deprecating range() with negative stride today to force people to
replace their uses of that with reversed(range(...)).

-- 
--Guido van Rossum (python.org/~guido)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20131027/2bd8b047/attachment.html>


More information about the Python-ideas mailing list