PYTHON / LISTS AND TUPLES
Slicing lists and slice assignment
Select any run of items with lst[start:stop:step] and use slice assignment or del to replace, insert, or remove whole regions of a list.
What you will learn
- Read sublists with lst[start:stop:step]; stop is excluded and out-of-range bounds clamp
- Travel backwards with a negative step, as in lst[::-1] or lst[5:2:-1]
- Replace, insert, or splice with lst[a:b] = iterable, even when lengths differ
- Remove a region with del lst[a:b]; step slices demand an exact length match
Understanding Slicing lists and slice assignment
Treat the numbers in a slice as labels for the gaps between items, not for the items themselves. lst[2:5] cuts before position 2 and before position 5 and hands back everything between those two cuts as a brand-new list, which is why the stop index is excluded and why 5 - 2 predicts the length. Because the result is a separate list object, sub = lst[2:5] followed by sub[0] = 'x' leaves lst alone.
The optional third number is the step, and a negative step reverses the direction of travel — it also reverses what an omitted end means, so lst[::-1] begins at the last item and walks down to the first. Slice bounds are clamped rather than checked: anything past the end is pulled back to the end, and a region that turns out to be empty simply produces [], with no IndexError. That asymmetry with lst[9] is deliberate, since a region can legitimately contain nothing while a single position either exists or it doesn't.
On the left of an assignment a slice stops meaning "items to copy" and starts meaning "region to overwrite". lst[1:3] = ['a', 'b', 'c'] deletes those two items and splices three in their place, so the list changes length; lst[2:2] = [...] inserts without deleting because the region is empty, and del lst[1:3] (or lst[1:3] = []) cuts the region out. The exception is an extended slice with a step other than 1: those target positions are scattered and fixed, so the right side must supply exactly as many values or Python raises ValueError.
letters = ['a', 'b', 'c', 'd', 'e', 'f']
print(letters[1:4])
print(letters[:3])
print(letters[3:])
print(letters[-2:])
print(letters[::2])
print(letters[::-1])
letters[1:3] = ['X', 'Y', 'Z'] # 2 items out, 3 items in
print(letters)
letters[0:0] = ['start'] # empty region: pure insert
print(letters)
del letters[1:3] # cut the region out
print(letters)A slice names a region of a list by cut points, so reading one copies that region and assigning to one replaces it, possibly with a different number of items.
Worked examples
Step slices need an exact length
Assigning through a slice with a step other than 1 only works when the right side has exactly as many items as the slice selects.
nums = [0, 1, 2, 3, 4, 5, 6, 7]
nums[::2] = ['a', 'b', 'c', 'd']
print(nums)
try:
nums[::2] = ['x', 'y']
except ValueError as e:
print('ValueError:', e)Example explained
Line 1nums[::2] selects positions 0, 2, 4, 6 — four fixed slots, so four values fit perfectly.
Line 2The odd-numbered positions are untouched, which is why 1, 3, 5, 7 survive unchanged.
Line 3With only two replacement values Python cannot decide which slots to leave alone, so it refuses instead of guessing.
Line 4A contiguous slice like nums[0:8] has no such rule because its items are adjacent and can shift.
Slices clamp, indexes don't
Out-of-range slice bounds are quietly trimmed to the ends of the list, while an out-of-range single index is an error.
data = [10, 20, 30]
print(data[1:99])
print(data[5:9])
print(data[-99:2])
try:
print(data[5])
except IndexError as e:
print('IndexError:', e)Example explained
Line 1data[1:99] clamps the stop to 3, so it returns everything from index 1 onward.
Line 2data[5:9] describes a region entirely past the end, which is empty rather than invalid.
Line 3data[-99:2] clamps the negative start up to 0, giving the first two items.
Line 4data[5] must name one existing element, so there is nothing to clamp and Python raises IndexError.
Negative steps and window reversal
A negative step walks from higher indexes to lower ones, and it can be combined with slice assignment to reverse part of a list.
row = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
print(row[5:2:-1])
print(row[2:5:-1])
print(row[:2:-1])
row[1:4] = row[3:0:-1]
print(row)Example explained
Line 1row[5:2:-1] starts at index 5 and steps down, stopping before index 2.
Line 2row[2:5:-1] is empty because a negative step can never move from a lower index to a higher one.
Line 3In row[:2:-1] the omitted start means the far end in the direction of travel, so it begins at 'g'.
Line 4The right side row[3:0:-1] is built first as ['d', 'c', 'b'], then written back over row[1:4], reversing that window in place.
Important notes
A slice builds a new list but stores the same element objects, so mutating a nested list found inside the slice is visible through the original.
Strings and tuples support the same read syntax, but slice assignment and del require a mutable sequence — a tuple raises TypeError.
Common mistakes
Writing lst[0:3] while expecting the item at index 3 to be included; the stop is excluded, so the last element is silently dropped with no error to warn you.
Assigning a non-list on the right: lst[1:2] = 'ab' splices 'a' and 'b' in as two separate items, and lst[1:2] = 5 fails with TypeError: can only assign an iterable.
Trying to reverse a chunk with lst[4:1] and getting [] instead; without a negative step Python only moves forward, so you need lst[4:1:-1].
Try it yourself
Change, predict, then run
Start from q = [1, 2, 3, 4, 5, 6] and, using only slices, print the last three items, then replace the items at indexes 1 and 2 with the single value 99, then delete every other remaining item, printing q after each change.
Open the Python workspaceCheck your understanding
After xs = [1, 2, 3, 4, 5] and xs[1:4] = [0], what is xs?
- [1, 0, 5]
- [1, 0, 3, 4, 5]
- [1, 0, 0, 0, 5]
- A ValueError, because 3 items cannot be replaced by 1
Show answer
xs[1:4] names the contiguous region 2, 3, 4; assigning to it removes all three and splices the single value 0 in, so the list shrinks to length 3. The ValueError option is tempting but that rule only applies to extended slices with a step other than 1, where the target positions are fixed and cannot shift.