[Python-Dev] Inclusive Range

Steve Howell showell30 at yahoo.com
Wed Oct 13 05:10:43 CEST 2010


On Oct 11, 1:40 am, Antoon Pardon <Antoon.Par... at rece.vub.ac.be>
wrote:
> On Sat, Oct 09, 2010 at 01:37:03AM +0000, Steven D'Aprano wrote:
> > On Fri, 08 Oct 2010 15:53:17 -0400, Jed Smith wrote:
>
> > > On Fri, Oct 8, 2010 at 1:26 PM, Steven D'Aprano
> > > <st... at remove-this-cybersource.com.au> wrote:
> > >> On Fri, 08 Oct 2010 10:21:16 +0200, Antoon Pardon wrote:
>
> > >>> Personnaly I find it horrible
> > >>> that in the following expression: L[a:b:-1], it is impossible to give
> > >>> a numeric value to b, that will include L[0] into the reversed slice.
>
> > >>>>> L = [1, 2, 3, 4, 5]
> > >>>>> L[5:-6:-1]
> > >> [5, 4, 3, 2, 1]
>
> > >>>> a = [1, 2, 3, 4, 5, 6]
> > >>>> a[::-1]
> > > [6, 5, 4, 3, 2, 1]
>
> > Well of course that works, that is the standard Python idiom for
> > reversing a sequence.
>
> > But the point was that Antoon claimed that there is no numeric value for
> > the end position that will include L[0] in the reversed slice. My example
> > shows that this is not correct.
>
> I stand by that claim. I think it was fairly obvious that what I meant
> was that it was impossible to give such a numeric value that would work
> with arbitrary L.
>
> if L2 == list(reversed(L1)) and a and b are in the range 1 < x <= len(L),
> we have the following invariant.
>
>   L1[a:b] == L2[b-1:a-1:-1]
>
> However this no longer works if either nr is 0. That means that if a and
> be are computed values, that may return 0 to indicate which slice you
> want; that if you want the reversed slice, there is no straightforward
> way to get that reversed slice with extended slice notation.
>

Here is a transformation that uses extended slice notation under the
hood, while preserving your semantics for 0 <= l <= h

  def reverse_list_slice(lst, l, h):
      if l == 0 and h == 0: return []
      h = h - 1 if h else None
      l = l - 1 if l else None
      return lst[h:l:-1]

It's not exactly elegant, but it's not a ton of code either.

Here is how I tested it:

  lst = [0, 1, 2, 3, 4]
  for a in range(len(lst)):
      for width in range(len(lst)-a):
          b = a + width
          print a, b
          rev1 = list(reversed(lst[a:b]))
          rev2 = reverse_list_slice(lst, a, b)
          if rev1 != rev2:
              print a, b
              print rev1
              print rev2
              raise 'invariant broken'

If you want to look at some of the internals for cpython, you can find
them here:

  http://svn.python.org/view/python/trunk/Objects/sliceobject.c?view=markup
  http://svn.python.org/view/python/trunk/Objects/listobject.c?view=markup

The basic iteration that happens is as follows:

            for (cur = start, i = 0; i < slicelength;
                 cur += step, i++) {
                it = src[cur];
                Py_INCREF(it);
                dest[i] = it;
            }



More information about the Python-list mailing list