slice's indices() method

smichr at gmail.com smichr at gmail.com
Mon Oct 30 05:11:52 EST 2006


It seems to me that the indices() method for slices is could be
improved. Right now it gives back concrete indices for a range of
length n. That is, it does not return any None values. Using an example
from clpy about this the indices for a 'None, None, -2' slice for a
range of length 10 are given as '9, -1, -2'. The problem is that these
concrete values cannot be fed back into a slice so that a slice will
extract the same elements that the 'None, None, -2' would have
extracted. That's where the problem is. It seems to me that the indices
given *from a slice object* should be able to make a round trip and and
be used as arguments for a slice object and extract the same elements
that the non-concrete (i.e. None-containin) indices would have given.
Instead, the behavior right now only allows these indices from a slice
object to be fed to a *range* object to give back the indices of the
elements that would have been extracted from the original lenght-n
object.

Here is the full example given in the clpy archives:

>>> slice(None, None, -2).indices(10)
(9, -1, -2)
>>> range(9, -1, -2)
[9, 7, 5, 3, 1]
>>> range(10)[slice(9, -1, -2)]
[]

Notice that although the indices given, (9, -1, -2), give a valid range
of values from 9 through 1 stepping by 2, these same indices don't
extract elements from a range when they are given as an argument to the
slice function. In essense, the slice 'None, None, -2' (or '::-2') is
not interpreted the same way as the explicitly specified values of '9,
-1, -2'. This seems unecessarily obtuse: since the indices *came* from
a slice object it seems to me that they should be able to *go back
into* a slice object; 'None, None, -2' and the indices obtained for a
length-10 object should behave the same.

In reading the discussion of Aug 2005 regarding this issue, it sounded
like the intent of slice.indices() was to get indices which could be
sent to range to generate a range whose values would match the indices
produced by the original slice and that this capability was mainly to
be used for unittest-ing. If the following sort of logic were applied
instead of the current logic I think it would improve the usability of
the indices() method for slices:

def sliceIndices(slc, n):
    start, stop, step = slc.indices(n)
    if cmp(stop-start,0)<>cmp(step,0): #null
        if step<0:
            if 0 not in [start-n,stop-n]:start-=n;stop-=n
        else:
            if start<0 or stop<0:start+=n;stop+=n
    else: #valid
        if step<0: #all should be less than 0
            if start>=0 or stop>=0:start-=n;stop-=n
    return start, stop, step

With this logic the following result is obtained for the same indices
used in the above examples:

>>> print sliceIndices(slice(None,None,-2),10)
(-1, -11, -2)
>>> range(-1, -11, -2)
[-1, -3, -5, -7, -9]
>>> range(10)[slice(-1, -11, -2)]
[9, 7, 5, 3, 1]

This modification of the indices will give indices which can be used in
a slice to extract the same elements from a length-n object as the
original slice or to generate a range whose elements correspond to the
indices of the elements extracted by the original slice.

I searched through the *.py scripts in the distribution library, and
the only place I found slice indices being used was in the script
testing slices...and the test were simply assertions that the
slice.indices() gave the expected tuple.

Is there any reason not to change the behavior of the indices() method
so it gives indices that can be used in range (to give indices
corresponding to elements that would be extracted by a given slice)
*and* used as arguments for slices so that the slice with the new
indices (obtained from the indices() method) would extract the same
elements as the original slice from whence they were obtained? Would
anything (except the present unittest for the indices() method) break
if this new behavior were implemented?

/chris




More information about the Python-list mailing list