Skip to content

Slicing

~15 min ยท prerequisite: Strings and Lists

What you will be able to do

  • Take a part of a string, list, or tuple with start:stop and get a new value back.
  • Use negative indexes, omitted bounds, and a step to reverse or skip items.
  • Predict what a slice gives when its bounds fall outside the sequence, and tell a slice error apart from an index error.

The idea

In lesson 1 you read one character with an index, such as word[0]. A slice reads a range of items at once. You write it inside square brackets with a colon: sequence[start:stop]. The value of start is the position of the first item you want. The value of stop is the position where you stop, and that item is not included. So "Python"[0:2] gives "Py", which is the items at positions 0 and 1.

Either bound may be left out. If you omit start, the slice begins at the first item. If you omit stop, it runs to the end. The slice "Python"[:3] gives "Pyt", and "Python"[3:] gives "hon". The slice "Python"[:] gives a copy of the whole sequence.

Negative numbers count from the end, as they do for a single index. The item at -1 is the last item, so "Python"[-3:] gives "hon". This also works in the middle: "Python"[1:-1] gives "ytho".

A third part, the step, controls how many positions you move each time. The slice sequence[start:stop:step] takes every stepth item. The slice [::2] takes every second item, and [::-1] takes every item in reverse order. Reversing is a common use, because "abc"[::-1] gives "cba".

A slice always gives back a new value of the same type. A slice of a string is a string, and a slice of a list is a list. The original sequence does not change. Slicing a list also gives you a copy, so copy = nums[:] is one way to make an independent list.

A slice does not raise an error when its bounds fall outside the sequence. Bounds that are too large are cut down to the end, and bounds that are too small are cut to the start. A single index does raise an error in that case, as lesson 1 showed.

Worked example

letters = "abcdefgh"
print(letters[2:5])
print(letters[:3])
print(letters[-3:])
print(letters[::2])
print(letters[::-1])

nums = [10, 20, 30, 40, 50]
print(nums[1:4])
print(nums[10:])

Line by line, this is what Python does:

  1. letters[2:5] starts at position 2, which is c, and stops before position 5. The result is cde.
  2. letters[:3] has no start, so it begins at the first item. The result is abc.
  3. letters[-3:] starts three items from the end, at f, and runs to the end. The result is fgh.
  4. letters[::2] has no start or stop and a step of 2. It takes a, c, e, g.
  5. letters[::-1] has a step of -1, so it walks backwards from the end. The result is hgfedcba.
  6. nums[1:4] gives the list items at positions 1, 2, and 3. Note that position 4 is excluded.
  7. nums[10:] starts past the end of the list. Python returns an empty list, and no error appears.

The output is:

cde
abc
fgh
aceg
hgfedcba
[20, 30, 40]
[]

Try it

The first block checks slices of a string. The second block checks slices of a list and that a slice is a new object. The third block checks steps and out-of-range bounds.

word = "Python"
assert word[0:2] == "Py"
assert word[:3] == "Pyt"
assert word[3:] == "hon"
assert word[-3:] == "hon"
assert word[1:-1] == "ytho"
assert word[:] == "Python"
nums = [10, 20, 30, 40, 50]
part = nums[1:4]
assert part == [20, 30, 40]
assert nums == [10, 20, 30, 40, 50]
part.append(99)
assert nums == [10, 20, 30, 40, 50]
copy = nums[:]
assert copy is not nums
assert copy == nums
letters = "abcdefgh"
assert letters[::2] == "aceg"
assert letters[1::2] == "bdfh"
assert letters[::-1] == "hgfedcba"
assert letters[100:] == ""
assert letters[2:100] == "cdefgh"
assert letters[5:2] == ""
assert (1, 2, 3)[1:] == (2, 3)

Common mistakes

  1. Expecting the stop item to be included. The code print("Python"[0:2]) prints Py, not Pyt. The item at position 2 is excluded. To include positions 0 to 2, write [0:3].

  2. Using an index where a slice is needed. The code word = "Python" followed by print(word[10]) gives:

    IndexError: string index out of range
    

    A single index must exist. A slice such as word[10:] gives an empty string instead.

  3. Using a step of zero. The code print([1, 2, 3][::0]) gives:

    ValueError: slice step cannot be zero
    

    The step tells Python how far to move each time, so it must not be zero.

  4. Expecting a slice to change the original. The code nums = [1, 2, 3] followed by nums[0:2] and print(nums) still shows [1, 2, 3]. A slice returns a new value. Assign it to a name if you want to keep it.

  5. Mixing up the order of the bounds. The slice "Python"[4:1] gives an empty string, because the stop is before the start. Read the bounds as "from here, up to but not including there".

Practice

  1. Create word = "scarlet". Assert that word[0:3] equals "sca", and that word[-2:] equals "et".
  2. Create nums = [1, 2, 3, 4, 5, 6]. Assert that nums[2:] equals [3, 4, 5, 6], and that nums[:2] equals [1, 2].
  3. Create text = "abcdef". Assert that text[::2] equals "ace", and that text[1::2] equals "bdf".
  4. Create phrase = "level". Build backwards with a slice. Assert that phrase == backwards, which is a palindrome check.
  5. Stretch: create nums = [0, 1, 2, 3, 4, 5, 6, 7]. Assert that nums[1:7:2] equals [1, 3, 5], and that nums[::-2] equals [7, 5, 3, 1].
Solution
  1. python word = "scarlet" assert word[0:3] == "sca" assert word[-2:] == "et"

  2. python nums = [1, 2, 3, 4, 5, 6] assert nums[2:] == [3, 4, 5, 6] assert nums[:2] == [1, 2]

  3. python text = "abcdef" assert text[::2] == "ace" assert text[1::2] == "bdf"

  4. python phrase = "level" backwards = phrase[::-1] assert phrase == backwards

  5. python nums = [0, 1, 2, 3, 4, 5, 6, 7] assert nums[1:7:2] == [1, 3, 5] assert nums[::-2] == [7, 5, 3, 1]

Recap

  • sequence[start:stop] gives the items from start up to, but not including, stop. Either bound can be omitted.
  • A third value, sequence[start:stop:step], skips items, and a step of -1 reverses the order.
  • A slice returns a new value of the same type, and it does not raise an error for bounds outside the sequence.

Sources