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

Terry Reedy tjreedy at udel.edu
Tue Oct 29 05:51:50 CET 2013


On 10/28/2013 10:25 PM, Steven D'Aprano wrote:
> On Mon, Oct 28, 2013 at 05:06:09PM -0400, Terry Reedy wrote:

>> I think where we went wrong with strides was to have the sign of the
>> stride affect the interpretation of i and j (in analogy with ranges).
>> The change is to correct this by decoupling steps 1. and 2. below. The
>> result is that i and j would mean left and right ends of the slice,
>> rather than 'start' and 'stop' ends of the slice.
>
> Sorry Terry, your paragraph above is ambiguous to me. It sounds like you
> are saying that having slices work by analogy with range was a mistake.

I once suggested that slice and range should be consolidated into one 
class. I was told (correctly, I see now) that no, slices and ranges are 
related but different. I have forgotten whatever explanation was given, 
but their parameters have different meanings. For slices, start and stop 
are symmetrical and both mark boundaries between what is included and 
what is excluded. For ranges, start and stop are symmetrical; one is 
included and the other excluded.

What I said above is that a negative stride is enough to say 'reverse 
the direction of selection (or replacement)'.  It is not actually 
necessary to also switch the endpoint arguments.

> Are you suggesting to break the analogy between slicing and range?

It was already broken, more than I really noticed until today.

> That is, range continues to work they way it currently does, but change
> slice?

Perhaps, but I read Guido's post less than 12 hours ago. Thinking about 
ranges is for another day.

>> Whether selecting or replacing, this proposal makes the rule for
>> indicating an arithmetic subsequence to be:
>>
>> 1. indicate the contiguous slice to work on with left and right
>> endpoints (left end i, right end j, i <= j after normalization with same
>> rules as at present);
>>
>> 2. indicate the starting end and direction of movement, left to right
>> (default) or right to left (negate k);
>>
>> 3. indicate whether to pick every member of the slice (k=1, default) or
>> every kth (k > 1), starting with the first item at the indicated end (if
>> there is one) and moving in the appropriate direction.
>
> "pick every kth element" works for k=1 as well as k > 1, no need for a
> special case here. Every 1th element is every element :-)

Right. The reason I special-cased 1 is that -1 is an unambiguous special 
case that can be used to define the -k for k>1 case. Currently, s[::-k] 
== s[::-1][::k]. It has been proposed to change that to s[::k][::-1], 
first by Tim (who changed his mind, as least for now) and perhaps by Nick.

>> My quick take on slicing versus indexing. The slice positions of a
>> single item are i:(i+1). The average is i.5. Some languages (0-based,
>> like Python) round this down to i, others (1-based) round up to i+1.

Because of my experience drawing graphs with dots representing objects 
and with axes with labelled tick marks, I think of slicing in terms of 
labelled tick marks with objects (or object references) 'centered' 
between the tick marks.

|_|_|
0 1 2

If a character is centered between the tick marks labelled 0 and 1, its 
'coordinate' would be .5. I agree that one could get to the same result 
by simply dropping one of the slice endpoints.

Another reason to think of the objects as being at half coordinates is 
that is explains the count correctly without introducing a spurious 
asymmetry. A slice from i to j includes (j-i)+1 slice positions if you 
include i and j or (j-i)-1 if you do not. It include j-i half 
coordinates, which is exactly how many items are included in the slice.

> I don't think it's helpful to talk about averaging or rounding the
> indexes. Better to talk about whether indexes are included or excluded,
> or whether the interval is open (end points are excluded) or closed (end
> points are included).

s[i:j] includes all items between slice positions i and j. I do not 
think that the concept open/closed really applies to slices, as opposed 
to arithmetic interval (whether discrete or continuous). Slicing uses 
slice coordinates, but does not include them in the slice. If one forces 
the concept on slices, the slice interval would be either open or closed 
at both ends. They are definitely not asymmetric, half one, half the 
other. However, the 'length' of a slice is the same as a half-open interval.

-- 
Terry Jan Reedy



More information about the Python-ideas mailing list