Programming and IT

Python: slicing

A slice cuts a piece out of a sequence by the rule "from which index, up to which, with what step". The notation is compact, but it has two places where almost everyone slips: the right bound is not included, and with a negative step the bounds swap places. Let us go through both.

Updated
In this article

How to read the notation#

The full form is sequence[start:stop:step]. The start is included, the stop is not. Any part can be omitted.

a = [0, 1, 2, 3, 4, 5]
print(a[1:4])    # [1, 2, 3]
print(a[:3])     # [0, 1, 2]
print(a[3:])     # [3, 4, 5]
print(a[:])      # [0, 1, 2, 3, 4, 5]
print(a[::2])    # [0, 2, 4]

The "stop is excluded" rule feels awkward until you notice two consequences: the length of a slice equals stop - start, and a[:i] and a[i:] together give the original list with no overlap and no gaps.

i = 2
print(a[:i] + a[i:] == a)    # True
print(len(a[1:4]))           # 3

Negative indexes and a negative step#

A negative index counts from the end: -1 is the last item, -2 the one before it.

print(a[-1])     # 5
print(a[-2:])    # [4, 5]   the last two
print(a[:-2])    # [0, 1, 2, 3]   everything except the last two

A negative step goes from right to left, and then the start must be to the right of the stop:

print(a[::-1])    # [5, 4, 3, 2, 1, 0]
print(a[4:1:-1])  # [4, 3, 2]
print(a[1:4:-1])  # []  — empty: we go left, but the stop is to the right

a[::-1] is the idiomatic way to reverse. Lists also have a reverse() method that changes the list in place; a slice returns a new one.

Slicing strings#

A string is a sequence too, so the rules are the same, but the result is a string, not a list of characters.

s = "programming"
print(s[:7])        # program
print(s[-5:])       # mming
print(s[::-1])      # gnimmargorp
print(s[::3])       # pgmn
print(s[4:4])       # an empty string

Slicing is handy for cutting fixed-format records: date[:4] is the year in "2026-09-21", date[5:7] is the month. For variable-length formats split is more reliable — see the article on Python strings.

A slice as a copy, and assigning to a slice#

a[:] creates a new list with the same items — a shallow copy:

b = a[:]
b.append(99)
print(len(a), len(b))    # 6 7

Nested objects stay shared, just as with a.copy(). More on that in the article on Python lists.

You can assign to a slice, and the length of the piece does not have to stay the same:

nums = [0, 1, 2, 3, 4]
nums[1:3] = ["a", "b", "c"]
print(nums)          # [0, 'a', 'b', 'c', 3, 4]
nums[0:2] = []       # deleting a piece
print(nums)          # ['b', 'c', 3, 4]
del nums[::2]
print(nums)          # ['c', 4]

You cannot do this with strings: they are immutable, and s[0:2] = "ab" raises TypeError.

Why the result is empty#

A slice never raises IndexError — beyond the bounds it simply returns whatever is there, down to nothing. That is convenient, but it hides bugs:

print(a[10:20])   # []   no such indexes — empty, no exception
print(a[10])      # IndexError: list index out of range
print(a[3:1])     # []   start to the right of stop with step +1
print(a[::0])     # ValueError: slice step cannot be zero

If a slice is unexpectedly empty, check in order: are the bounds swapped, do you need a negative step, did you count the stop as inclusive? A quick self-check is to print len(result) next to the number you expected.

Practice: take a list of twenty numbers and, in one line, get every third item counting from the end; then split the list into chunks of five with [a[i:i + 5] for i in range(0, len(a), 5)] — you will need this idiom often.

Step-by-step plan

  1. Three simple slicesOn a six-item list, get the first three, the last two and a copy of the whole list.
  2. Step and reversePrint every second item and reverse the sequence with [::-1].
  3. Negative boundsGet "everything except the last two" and "the last two" and compare with the original length.
  4. Assign to a sliceReplace two items with three and delete a piece with nums[i:j] = [].
  5. Split into chunksCut a list of twenty numbers into chunks of five with a list comprehension and a slice.

Start learning this in your own space

The plan goes into your repository: tick off stages, keep notes — the change history shows how far you have come.

Start the plan

Check yourself

1.What is len([0, 1, 2, 3, 4, 5][1:4])?

2.What does print("python"[::-1]) print?

3.What is len([0, 1, 2, 3, 4, 5][3:1])?

4.What does print([0, 1, 2, 3, 4][1:3]) print?

Sources

Was this helpful?

More articles

Programming and IT Python: lists A list is a mutable, ordered collection of values of any type. It is also the main source of surprises for beginners: assignment does not copy a list, sort returns nothing, and removing items inside a loop skips half of them. Let us go through it in order. Programming and IT Python: strings A string in Python is an immutable sequence of characters. Almost all of its quirks follow from that: methods do not change a string but return a new one, and fast text building goes through join, not through adding strings in a loop. Below is the working minimum with examples and output. Programming and IT How to learn Python from scratch Python is a good first programming language: code reads almost like text, and the standard library covers most everyday tasks. This plan takes you from installing the interpreter to your own scripts covered by tests in about four months, at roughly an hour a day. Programming and IT Python: regular expressions A regular expression is a pattern that describes a set of strings. In Python you work with them through the `re` module from the standard library. You write the pattern as a string with an `r` prefix, search with `re.search` and pull the result out of a match object. Everything else is details of the pattern language. Programming and IT Python: generators A generator hands out values one at a time, and only when someone asks for them. It does not keep the whole sequence in memory, so it suits large files and endless streams. The price is that a generator is single-use: you cannot loop over it twice. Programming and IT Python: classes A class describes what data an object is made of and what it can do. The `__init__` constructor fills in a new object, and `self` is a reference to the object itself. Below: a minimal working class, the difference between class and instance attributes, and ways to make the code shorter.

More solutions