4707

How does Python's slice notation work? That is: when I write code like a[x:y:z], a[:], a[::2] etc., how can I understand which elements end up in the slice?


See Why are slice and range upper-bound exclusive? to learn why xs[0:2] == [xs[0], xs[1]], not [..., xs[2]].
See Make a new list containing every Nth item in the original list for xs[::N].
See How does assignment work with list slices? to learn what xs[0:2] = ["a", "b"] does.

0

38 Answers 38

1
2
9

I don't think that the Python tutorial diagram (cited in various other answers) is good as this suggestion works for positive stride, but it does not for a negative stride.

This is the diagram:

 +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
 0   1   2   3   4   5   6
-6  -5  -4  -3  -2  -1

From the diagram, I expect a[-4,-6,-1] to be yP, but it is ty.

>>> a = "Python"
>>> a[2:4:1] # as expected
'th'
>>> a[-4:-6:-1] # off by 1
'ty'

It always work to think in characters or slots and use indexing as a half-open interval—right-open if positive stride and left-open if negative stride.

This way, I can think of a[-4:-6:-1] as a(-6,-4] in interval terminology.

 +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
   0   1   2   3   4   5
  -6  -5  -4  -3  -2  -1

 +---+---+---+---+---+---+---+---+---+---+---+---+
 | P | y | t | h | o | n | P | y | t | h | o | n |
 +---+---+---+---+---+---+---+---+---+---+---+---+
  -6  -5  -4  -3  -2  -1   0   1   2   3   4   5
Sign up to request clarification or add additional context in comments.

3 Comments

Used today 2021/07/19 by myself, qué capo aguadopd del pasado
As a newbie, this is an interesting way of thinking about it. However, the last example, counting from -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 is a bit misleading because the string is NOT doubled like that. Furthermore, one can refer to the positive and negate positions like the following: a[-4:-6:-1] is the same as a[-4:0:-1] since the 0th position is the same as the -6th position. So I would just delete/ignore that example.
Great observation! This also matches how one thinks about regular indexing. But "between characters" thinking helps grok the very handy idioms a[:N] take first N, a[N:] drop first N, a[-N:] take last N, a[:-N] drop last N. IMHO step<0 makes indexes just too confusing, and better reverse in separate step when possible, e.g. "Python"[2:4][::-1] == "ht"
8

The basic slicing technique is to define the starting point, the stopping point, and the step size—also known as stride.

First, we will create a list of values to use in our slicing.

Create two lists to slice. The first is a numeric list from 1 to 9 (List A). The second is also a numeric list, from 0 to 9 (List B):

A = list(range(1, 10, 1)) # Start, stop, and step
B = list(range(9))

print("This is List A:", A)
print("This is List B:", B)

Index the number 3 from A and the number 6 from B.

print(A[2])
print(B[6])

Basic Slicing

Extended indexing syntax used for slicing is aList[start:stop:step]. The start argument and the step argument both default to None—the only required argument is stop. Did you notice this is similar to how range was used to define lists A and B? This is because the slice object represents the set of indices specified by range(start, stop, step).

As you can see, defining only stop returns one element. Since the start defaults to none, this translates into retrieving only one element.

It is important to note, the first element is index 0, not index 1. This is why we are using 2 lists for this exercise. List A's elements are numbered according to the ordinal position (the first element is 1, the second element is 2, etc.) while List B's elements are the numbers that would be used to index them ([0] for the first element, 0, etc.).

With extended indexing syntax, we retrieve a range of values. For example, all values are retrieved with a colon.

A[:]

To retrieve a subset of elements, the start and stop positions need to be defined.

Given the pattern aList[start:stop], retrieve the first two elements from List A.

Comments

6

For simple way and simple understandable:

In Python, the slice notation a[start:stop:step] can be used to select a range of elements from a sequence (such as a list, tuple, or string).

The start index is the first element that is included in the slice,

The stop index is the first element that is excluded from the slice, and last one

The step value is the number of indices between slice elements.

For example, consider the following list:

a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

If we want to select all elements of a, we can use the slice notation a[:]:

>>> a[:]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

If we want to select all elements of a, but skip every other element, we can use the slice notation a[::2]:

>>> a[::2]
[0, 2, 4, 6, 8]

If we want to select all elements from the third element (index 2) to the seventh element (index 6), we can use the slice notation a[2:7]:

>>> a[2:7]
[2, 3, 4, 5, 6]

If we want to select all elements from the third element (index 2) to the seventh element (index 6), but skip every other element, we can use the slice notation a[2:7:2]:

>>> a[2:7:2]
[2, 4, 6]

If we want to select all elements from the third element (index 2) to the end of the list, we can use the slice notation a[2:]:

>>> a[2:]
[2, 3, 4, 5, 6, 7, 8, 9]

If we want to select all elements from the beginning of the list to the seventh element (index 6), we can use the slice notation a[:7]:

>>> a[:7]
[0, 1, 2, 3, 4, 5, 6]

If you want to learn more about slice notation, you can refer to the official Python documentation: Link 1 Link 2

Comments

5

I got a little frustrated in not finding an online source, or Python documentation that describes precisely what slicing does.

I took Aaron Hall's suggestion, read the relevant parts of the CPython source code, and wrote some Python code that performs slicing similarly to how it's done in CPython. I've tested my code in Python 3 on millions of random tests on integer lists.

You may find the references in my code to the relevant functions in CPython helpful.

def slicer(x, start=None, stop=None, step=None):
    """ Return the result of slicing list x.  

    See the part of list_subscript() in listobject.c that pertains 
    to when the indexing item is a PySliceObject.
    """

    # Handle slicing index values of None, and a step value of 0.
    # See PySlice_Unpack() in sliceobject.c, which
    # extracts start, stop, step from a PySliceObject.
    maxint = 10000000       # A hack to simulate PY_SSIZE_T_MAX
    if step is None:
        step = 1
    elif step == 0:
        raise ValueError('slice step cannot be zero')

    if start is None:
        start = maxint if step < 0 else 0
    if stop is None:
        stop = -maxint if step < 0 else maxint

    # Handle negative slice indexes and bad slice indexes.
    # Compute number of elements in the slice as slice_length.
    # See PySlice_AdjustIndices() in sliceobject.c
    length = len(x)
    slice_length = 0

    if start < 0:
        start += length
        if start < 0:
            start = -1 if step < 0 else 0
    elif start >= length:
        start = length - 1 if step < 0 else length

    if stop < 0:
        stop += length
        if stop < 0:
            stop = -1 if step < 0 else 0
    elif stop > length:
        stop = length - 1 if step < 0 else length

    if step < 0:
        if stop < start:
            slice_length = (start - stop - 1) // (-step) + 1
    else:
        if start < stop:
            slice_length = (stop - start - 1) // step + 1

    # Cases of step = 1 and step != 1 are treated separately
    if slice_length <= 0:
        return []
    elif step == 1:
        # See list_slice() in listobject.c
        result = []
        for i in range(stop - start):
            result.append(x[i+start])
        return result
    else:
        result = []
        cur = start
        for i in range(slice_length):
            result.append(x[cur])
            cur += step
        return result

1 Comment

I read all the relevant documents and found that there was no description of this syntax. I doubted my ability and felt relieved after seeing this answer. Maybe there was none.
3

It is easy to understand if we could relate slicing to range, which gives the indexes. We can categorize slicing into the following two categories:


1. No step or step > 0. For example, [i:j] or [i:j:k] (k>0)

Suppose the sequence is s=[1,2,3,4,5].

  • if 0<i<len(s) and 0<j<len(s), then [i:j:k] -> range(i,j,k)

For example, [0:3:2] -> range(0,3,2) -> 0, 2

  • if i>len(s) or j>len(s), then i=len(s) or j=len(s)

For example, [0:100:2] -> range(0,len(s),2) -> range(0,5,2) -> 0, 2, 4

  • if i<0 or j<0, then i=max(0,len(s)+i) or j=max(0,len(s)+j)

For example, [0:-3:2] -> range(0,len(s)-3,2) -> range(0,2,2) -> 0

For another example, [0:-1:2] -> range(0,len(s)-1,2) -> range(0,4,2) -> 0, 2

  • if i is not specified, then i=0

For example, [:4:2] -> range(0,4,2) -> range(0,4,2) -> 0, 2

  • if j is not specified, then j=len(s)

For example, [0::2] -> range(0,len(s),2) -> range(0,5,2) -> 0, 2, 4


2. Step < 0. For example, [i:j:k] (k<0)

Suppose the sequence is s=[1,2,3,4,5].

  • if 0<i<len(s) and 0<j<len(s), then [i:j:k] -> range(i,j,k)

For example, [5:0:-2] -> range(5,0,-2) -> 5, 3, 1

  • if i>len(s) or j>len(s), then i=len(s)-1 or j=len(s)-1

For example, [100:0:-2] -> range(len(s)-1,0,-2) -> range(4,0,-2) -> 4, 2

  • if i<0 or j<0, then i=max(-1,len(s)+i) or j=max(-1,len(s)+j)

For example, [-2:-10:-2] -> range(len(s)-2,-1,-2) -> range(3,-1,-2) -> 3, 1

  • if i is not specified, then i=len(s)-1

For example, [:0:-2] -> range(len(s)-1,0,-2) -> range(4,0,-2) -> 4, 2

  • if j is not specified, then j=-1

For example, [2::-2] -> range(2,-1,-2) -> 2, 0

For another example, [::-1] -> range(len(s)-1,-1,-1) -> range(4,-1,-1) -> 4, 3, 2, 1, 0


In summary

enter image description here

1 Comment

nit: For k<0, i and j get clipped to len(s)-1 not only when > len(s) but also when equal len(s). I think you can summarize by >= len(s) in left column?
1

You can use slice syntax to return a sequence of characters.

Specify a start and end index, separated by colons, to return part of the string.

Example:

Get the characters from position 2 to position 5 (not included):

b = "Hello, World!"
print(b[2:5])

Slice From the Start

By omitting the starting index, the range will start from the first character:

Example:

Get the characters from the start to position 5 (not included):

b = "Hello, World!"
print(b[:5])

Slice To the End

By omitting the end index, the range will end:

Example:

Get the characters from position 2, and all the way to the end:

b = "Hello, World!"
print(b[2:])

Negative Indexing

Use a negative index to start slicing from the end of the string: example.

Get the characters:

From: "o" in "World!" (position -5)

To, but not included: "d" in "World!" (position -2):

b = "Hello, World!"
print(b[-5:-2])

Comments

1

There are lots of answers already, but I wanted to add a performance comparison:

python3.8 -m timeit -s 'fun = "this is fun;slicer = slice(0, 3)"' "fun_slice = fun[slicer]"
10000000 loops, best of 5: 29.8 nsec per loop

python3.8 -m timeit -s 'fun = "this is fun"' "fun_slice = fun[0:3]"
10000000 loops, best of 5: 37.9 nsec per loop

python3.8 -m timeit -s 'fun = "this is fun"' "fun_slice = fun[slice(0, 3)]"
5000000 loops, best of 5: 68.7 nsec per loop

python3.8 -m timeit -s 'fun = "this is fun"' "slicer = slice(0, 3)"
5000000 loops, best of 5: 42.8 nsec per loop

So, if you are using the same slice repeatedly, it would be beneficial and improve readability to use a slice object. However, if you are slicing only a handful of times, the [:] notation should be preferred.

Comments

-8

Here's a simple mnemonic for remembering how it works:

  • S L *I* C *E*
  • the 'i' of slice comes first and stands for inclusive,
  • the 'e' comes last and stands for exclusive.

So array[j:k] will include the jth element and exclude the kth element.

3 Comments

You forgot the step like [j:k:s]. And slicing wraps around the list
But for the case I cover, array[j:k], I believe my mnemonic is correct and helpful. I don't believe it is wrong in any way. Please reconsider your downvote.
Your answer is incomplete, though, as it doesn't completely answer about different ways to slice. Other answers given already specify the inclusive/exclusive details
1
2

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.