Python Mutable Sequence
What Is a Mutable Sequence?
A mutable sequence in Python is an ordered collection of items that can be changed after its creation. This means you can add, remove, or modify elements at specific positions. Common built-in examples include lists and bytearrays.
The collections.abc.MutableSequence
abstract base class (ABC) defines the common interface for mutable sequence types. It inherits from Sequence
, meaning a MutableSequence
is also expected to be sized, iterable, a container, reversible, and support indexed access.
Required Methods and Inherited Functionality
To conform to the MutableSequence
ABC, a class must implement the following methods:
__getitem__(self, index)
: Returns the item at the givenindex
(inherited fromSequence
).__setitem__(self, index, value)
: Sets the item at the givenindex
tovalue
.__delitem__(self, index)
: Deletes the item at the givenindex
.__len__(self)
: Returns the number of items in the sequence (inherited fromSequence
).insert(self, index, value)
: Insertsvalue
beforeindex
.
From its parent ABC (Sequence
), MutableSequence
automatically gains mixin methods for many operations, including:
__contains__
__iter__
__reversed__
count
index
append
clear
reverse
extend
pop
remove
__iadd__
(for in-place concatenation)
from collections.abc import MutableSequence
from typing import Any, Union, Iterator
class MyCustomList(MutableSequence):
def __init__(self, initial_data: list[Any] = None) -> None:
self._data = list(initial_data) if initial_data is not None else []
def __getitem__(self, index: Union[int, slice]) -> Any:
return self._data[index]
def __setitem__(self, index: Union[int, slice], value: Any) -> None:
self._data[index] = value
def __delitem__(self, index: Union[int, slice]) -> None:
del self._data[index]
def __len__(self) -> int:
return len(self._data)
def insert(self, index: int, value: Any) -> None:
self._data.insert(index, value)
# The following methods are provided by MutableSequence ABC mixins:
# def append(self, value: Any) -> None:
# self._data.append(value)
# def clear(self) -> None:
# self._data.clear()
# def reverse(self) -> None:
# self._data.reverse()
# def extend(self, iterable: Iterable[Any]) -> None:
# self._data.extend(iterable)
# def pop(self, index: int = -1) -> Any:
# return self._data.pop(index)
# def remove(self, value: Any) -> None:
# self._data.remove(value)
# def __iadd__(self, other: Iterable[Any]) -> 'MyCustomList':
# self._data.__iadd__(other)
# return self
# Example usage:
my_list = MyCustomList([1, 2, 3])
print(f"Initial list: {my_list}") # Output: Initial list: [1, 2, 3]
my_list[1] = 20 # __setitem__
print(f"After changing index 1: {my_list}") # Output: After changing index 1: [1, 20, 3]
my_list.insert(0, 0) # insert
print(f"After inserting 0 at index 0: {my_list}") # Output: After inserting 0 at index 0: [0, 1, 20, 3]
del my_list[2] # __delitem__
print(f"After deleting index 2: {my_list}") # Output: After deleting index 2: [0, 1, 3]
my_list.append(4) # Mixin method
print(f"After appending 4: {my_list}") # Output: After appending 4: [0, 1, 3, 4]
print(f"Length: {len(my_list)}") # Output: Length: 4
Using collections.abc.MutableSequence
You can check if a class or object is a mutable sequence using isinstance
or issubclass
:
from collections.abc import MutableSequence
class AnotherMutableSequence:
def __init__(self, data: list[Any]) -> None:
self._data = data
def __getitem__(self, index: Union[int, slice]) -> Any:
return self._data[index]
def __setitem__(self, index: Union[int, slice], value: Any) -> None:
self._data[index] = value
def __delitem__(self, index: Union[int, slice]) -> None:
del self._data[index]
def __len__(self) -> int:
return len(self._data)
def insert(self, index: int, value: Any) -> None:
self._data.insert(index, value)
print(issubclass(AnotherMutableSequence, MutableSequence)) # True
print(isinstance(AnotherMutableSequence([1,2,3]), MutableSequence)) # True
# Built-in mutable sequence types also conform:
print(isinstance([], MutableSequence)) # True (list)
print(isinstance(bytearray(), MutableSequence)) # True (bytearray)
It's generally recommended to inherit directly from collections.abc.MutableSequence
(or other relevant ABCs) when designing your custom mutable sequence classes. This makes your code more explicit about its intended interface and can help static analysis tools. However, it's not strictly mandatory; Python's duck typing means that if your class implements the required methods (__getitem__
, __setitem__
, __delitem__
, __len__
, and insert
), it will be recognized as a mutable sequence, even without explicit inheritance from the ABC.
Key Takeaways
- A
MutableSequence
is an ordered, changeable collection accessible by index. - It requires
__getitem__
,__setitem__
,__delitem__
,__len__
, andinsert
. - It inherits extensive functionality from
Sequence
.