Python Slice Assignment: Modifying Sequences in Place
Python slice assignment is a powerful mechanism that allows developers to replace, insert, or delete elements in mutable sequences like lists directly in place without creating a new object. This article explains how slice assignment works under the hood, covering continuous slices, variable-length insertions, deletions, and the strict sizing rules required by extended step slices.
The In-Place Mechanism
When you assign a value to a slice of a mutable sequence, Python
invokes the object's __setitem__ method with a
slice object as the key. Unlike standard variable
reassignment (a = [1, 2]), which changes the reference to a
new object in memory, slice assignment alters the internal array of
pointers of the existing sequence. The memory address
(id()) of the sequence remains unchanged.
numbers = [1, 2, 3, 4]
original_id = id(numbers)
numbers[1:3] = [20, 30]
print(numbers) # Output: [1, 20, 30, 4]
print(id(numbers) == original_id) # Output: TrueContinuous Slice
Assignment ([start:stop])
Continuous slices do not require the replacement iterable to have the same length as the slice being replaced. Python automatically resizes the underlying array to accommodate the change.
Replacement
If the replacement sequence matches the length of the slice, elements are updated one-to-one:
items = ['a', 'b', 'c', 'd']
items[1:3] = ['x', 'y']
# Result: ['a', 'x', 'y', 'd']Insertion and Expansion
If the replacement contains more items than the target slice, Python shifts subsequent elements to the right to make room:
items = ['a', 'd']
items[1:1] = ['b', 'c'] # Empty slice insertion at index 1
# Result: ['a', 'b', 'c', 'd']Deletion and Shrinking
If the replacement contains fewer items or is an empty iterable, Python removes the sliced elements and shifts trailing elements to the left:
items = [1, 2, 3, 4, 5]
items[1:4] = []
# Result: [1, 5]Using items[:] = [] clears the list while preserving
references held by other variables.
Extended Slice
Assignment ([start:stop:step])
When a step argument is provided and is not equal to
1, Python treats the operation as an extended slice. Unlike
continuous slices, extended slices cannot resize the sequence.
The replacement iterable must contain the exact number of elements
selected by the slice. If the lengths do not match, Python raises a
ValueError.
numbers = [0, 1, 2, 3, 4, 5]
# Slice numbers[::2] selects 3 elements: indices 0, 2, and 4
numbers[::2] = [10, 20, 30]
# Result: [10, 1, 20, 3, 30, 5]
# This raises ValueError: attempt to assign sequence of size 2 to extended slice of size 3
# numbers[::2] = [10, 20]Iterable Requirements
The right-hand side of a slice assignment must be an iterable (such
as a list, tuple, generator, or
range). Assigning a non-iterable directly to a slice raises
a TypeError.
items = [1, 2, 3]
# items[0:2] = 10 # Raises TypeError: can only assign an iterable
items[0:2] = [10] # Valid: replaces two items with one item -> [10, 3]