87
votes

in the following example:

foo = ['red', 'white', 'blue', 1, 2, 3]

where: foo[0:6:1] will print all elements in foo. However, foo[6:0:-1] will omit the 1st or 0th element.

>>> foo[6:0:-1]
[3, 2, 1, 'blue', 'white']

I understand that I can use foo.reverse() or foo[::-1] to print the list in reverse, but I'm trying to understand why foo[6:0:-1] doesn't print the entire list?

8
Note also the foo[7:None:-1] possibility :) - tzot
I never used python before just trying to understand slice notation, my question is why foo[6:0:-1] is not throwing out of index error, does python not care about it? because 6 index is not available in above example array. - Mubashar
@MubasharAhmad Slicing is not indexing and does not throw out any error when going beyond the bounds. Indexing does throw exception when out of bounds, though. - huggie

8 Answers

165
votes

Slice notation in short:

[ <first element to include> : <first element to exclude> : <step> ]

If you want to include the first element when reversing a list, leave the middle element empty, like this:

foo[::-1]

You can also find some good information about Python slices in general here:
Explain Python's slice notation

12
votes

If you are having trouble remembering slice notation, you could try doing the Hokey Cokey:

[In: Out: Shake it all about]

[First element to include: First element to leave out: The step to use]

YMMV

7
votes

...why foo[6:0:-1] doesn't print the entire list?

Because the middle value is the exclusive, rather than inclusive, stop value. The interval notation is [start, stop).

This is exactly how [x]range works:

>>> range(6, 0, -1)
[6, 5, 4, 3, 2, 1]

Those are the indices that get included in your resulting list, and they don't include 0 for the first item.

>>> range(6, -1, -1)
[6, 5, 4, 3, 2, 1, 0]

Another way to look at it is:

>>> L = ['red', 'white', 'blue', 1, 2, 3]
>>> L[0:6:1]
['red', 'white', 'blue', 1, 2, 3]
>>> len(L)
6
>>> L[5]
3
>>> L[6]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

The index 6 is beyond (one-past, precisely) the valid indices for L, so excluding it from the range as the excluded stop value:

>>> range(0, 6, 1)
[0, 1, 2, 3, 4, 5]

Still gives you indices for each item in the list.

6
votes

This answer might be a little outdated, but it could be helpful for someone who stuck with same problem. You can get reverse list with an arbitrary end - up to 0 index, applying second in-place slice like this:

>>> L = list(range(10))
>>> L
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> (start_ex, end) = (7, 0)
>>> L[end:start_ex][::-1]
[6, 5, 4, 3, 2, 1, 0]
1
votes

Use

>>>foo[::-1]

This displays the reverse of the list from the end element to the start,

1
votes

You can get it to work if you use a negative stop value. Try this:

foo[-1:-7:-1]
0
votes

Complement. to reverse step by 2:

A = [1,2,2,3,3]
n = len(A)
res = [None] * n
mid = n//2 + 1 if n%2 == 1 else n//2

res[0::2] = A[0:mid][::-1]
res[1::2] = A[0:mid][::-1]
print(res)

[2, 3, 2, 3, 1]

0
votes

formalizing the answer from andrew-clark a little bit more:

Suppose the list v and v[n1:n2:n3] slice. n1 is initial position, n2 is final position and n3 is step

Let's write some pseucode in a Python way:

n3 = 1  if (n3 is missing) else n3
if n3==0:
   raise exception # error, undefined step

First part: n3 positive

if n3>0:
   slice direction is from left to right, the most common direction         

   n1 is left slice position in `v` 
   if n1 is missing: 
      n1 = 0   # initial position
   if n1>=0:
      n1 is a normal position
   else: 
     (-n1-1) is the position in the list from right to left 

   n2 is right slice position in `v` 
   if n2 is missing: 
      n2 = len(x)  # after final position
   if n2>=0:
      n2 is a normal final position (exclusive)
   else: 
      -n2-1 é the final position in the list from right to left 
       (exclusive)

Second part: n3 negative

else: 
  slice direction is from right to left (inverse direction)

  n1 is right slice position in `v` 
  if n1 is missing: 
     n1 = -1   # final position is last position in the list.
  if n1>=0:
     n1 is a normal position
  else: 
     (-n1-1) is the position in the list from right to left 

  n2 is  left slice position in `v` 
  if n2 is missing: 
     n2 = -len(x)-1   # before 1st character  (exclusive)
  if n2>=0:
     n2 is a normal final position (exclusive)
  else: 
     -n2-1 is the ending position in the list from right to left 
     (exclusive)

Now the original problema: How to reverse a list with slice notation?

L = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(L(::-1)) # [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

Why?
n1 is missing and n3<0 => n1=0
n2 is missing and n3<0 => n2 = -len(x)-1

So L(::-1) == L(-1:-11:-1)