Slicing
Slicing lets you pull out a sub-range of a sequence — a string, list, or
tuple — using a compact [start:stop:step] syntax. It is one of the
most-used pieces of Python syntax, and because it works the same way across
every built-in sequence type, learning it once pays off everywhere.
The start:stop:step Syntax
A slice is written as sequence[start:stop:step]. start is the index of
the first item included, stop is the index before which slicing stops
(the item at stop is never included — stop is exclusive), and step
is how many positions to advance between items.
letters = ["a", "b", "c", "d", "e", "f", "g"] # 0 1 2 3 4 5 6 print(letters[1:4]) # ['b', 'c', 'd'] - indices 1, 2, 3 (4 is excluded) print(letters[0:7:2]) # ['a', 'c', 'e', 'g'] - every 2nd item print(letters[2:2]) # [] - start == stop, so nothing is included
Negative Indices
Negative numbers count from the end of the sequence: -1 is the last item, -2 the second-to-last, and so on. You can mix positive and negative indices freely within the same slice.
letters = ["a", "b", "c", "d", "e", "f", "g"] print(letters[-3:]) # ['e', 'f', 'g'] - last 3 items print(letters[:-2]) # ['a', 'b', 'c', 'd', 'e'] - everything except the last 2 print(letters[-5:-2]) # ['c', 'd', 'e']
Omitting start, stop, or step
Any of the three parts can be left out, and each has a sensible default:
start defaults to the beginning of the sequence, stop defaults to the
end, and step defaults to 1.
Slice | Meaning | Example on [10, 20, 30, 40, 50] |
|---|---|---|
| Copy the whole sequence | [10, 20, 30, 40, 50] |
| From index 2 to the end | [30, 40, 50] |
| From the start up to (not including) index 3 | [10, 20, 30] |
| Every 2nd item, start to end | [10, 30, 50] |
| Index 1 up to 4, every 2nd item | [20, 40] |
| The whole sequence, reversed | [50, 40, 30, 20, 10] |
numbers = [10, 20, 30, 40, 50] print(numbers[:]) # [10, 20, 30, 40, 50] - a shallow copy of the whole list print(numbers[2:]) # [30, 40, 50] print(numbers[:3]) # [10, 20, 30] print(numbers[::2]) # [10, 30, 50]
Reversing with [::-1]
Using a negative step of -1 with no start or stop walks the sequence from
the end to the beginning, which makes [::-1] the idiomatic one-liner for
reversing a string, list, or tuple without mutating the original.
text = "Python" print(text[::-1]) # nohtyP digits = [1, 2, 3, 4, 5] print(digits[::-1]) # [5, 4, 3, 2, 1] print(digits) # [1, 2, 3, 4, 5] - original list is untouched
Slicing Works the Same Across Sequence Types
Strings, lists, and tuples are all sequence types, and the exact same
[start:stop:step] rules apply to each of them. The only difference is what
kind of object the slice returns: slicing a string returns a string, slicing
a list returns a list, and slicing a tuple returns a tuple.
s = "abcdefg"
l = ["a", "b", "c", "d", "e", "f", "g"]
t = ("a", "b", "c", "d", "e", "f", "g")
print(s[1:4]) # 'bcd' (str)
print(l[1:4]) # ['b', 'c', 'd'] (list)
print(t[1:4]) # ('b', 'c', 'd') (tuple)Slice Assignment (Lists Only)
Because lists are mutable, you can assign to a slice to replace, grow, shrink, or delete a chunk of a list in place. Strings and tuples are immutable, so slice assignment only works on lists.
numbers = [1, 2, 3, 4, 5] # Replace a sub-range - the new value doesn't need to be the same length numbers[1:4] = [20, 30] print(numbers) # [1, 20, 30, 5] numbers = [1, 2, 3, 4, 5] numbers[1:1] = [100, 200] # inserts without removing anything print(numbers) # [1, 100, 200, 2, 3, 4, 5] numbers = [1, 2, 3, 4, 5] del numbers[1:3] # deletes a chunk in place print(numbers) # [1, 4, 5]
The Built-in slice() Object
Every start:stop:step you write inside square brackets is actually
constructing a slice object behind the scenes. You can create one
explicitly with the slice() built-in and reuse it across multiple
sequences, which is handy when the same slicing pattern applies in several
places in your code.
middle = slice(1, 5, 2) numbers = [10, 20, 30, 40, 50, 60] letters = ["a", "b", "c", "d", "e", "f"] print(numbers[middle]) # [20, 40] print(letters[middle]) # ['b', 'd']