An efficient, immutable, type-safe copy-on-write (COW) list implementation for Python 2+.
Project description
COWList 🐄 -- An Immutable, Copy-on-Write List for Python
An efficient, immutable, type-safe copy-on-write (COW) list implementation for Python 2+.
COWList provides a persistent, immutable list-like data structure where all mutating operations return a new instance, allowing shared storage between list versions until modifications are made. This results in efficient memory use, O(1) indexing, and safe concurrency patterns.
Features
- ✅ Immutable: All operations return a new instance.
- 🧠 Copy-on-Write: Physical storage is shared until a mutation is required.
- ⚡ Efficient:
- O(1) indexing and slicing
- O(1) appending (if the current instance is contiguous and not a sliced view)
- O(k) extending (if the current instance is contiguous and not a sliced view)
- 🧩 Pythonic: Implements the full
collections.abc.Sequenceprotocol. Fully typed. - 🔐 Hashable: Suitable for use as dict keys or set elements (when elements are hashable).
- 🧪 Testable & Extendable: Clean architecture for experimentation or educational purposes.
Installation
pip install cowlist
Usage
from cowlist import COWList
# --- Construction ---
lst = COWList([1, 2, 3])
assert list(lst) == [1, 2, 3]
empty = COWList()
assert list(empty) == []
assert len(empty) == 0
# --- Immutability ---
lst2 = lst.append(4)
assert list(lst) == [1, 2, 3] # Original unchanged
assert list(lst2) == [1, 2, 3, 4] # New list with appended value
# --- Indexing and slicing ---
assert lst[0] == 1
assert lst[-1] == 3
assert list(lst[:2]) == [1, 2]
# --- Equality and hashing ---
lst_copy = COWList([1, 2, 3])
assert lst == lst_copy
assert hash(lst) == hash(lst_copy)
# --- Append ---
lst_app = lst.append(9)
assert list(lst_app) == [1, 2, 3, 9]
# --- Insert ---
lst_ins = lst.insert(1, 99)
assert list(lst_ins) == [1, 99, 2, 3]
# --- Extend ---
lst_ext = lst.extend([4, 5])
assert list(lst_ext) == [1, 2, 3, 4, 5]
# --- Delete by index ---
lst_del = lst.delete(1)
assert list(lst_del) == [1, 3]
# --- Delete by slice ---
lst_del_slice = lst.delete(slice(1, 3))
assert list(lst_del_slice) == [1]
# --- Remove value ---
lst_rem = lst.remove(2)
assert list(lst_rem) == [1, 3]
# --- Set by index ---
lst_set = lst.set(1, 42)
assert list(lst_set) == [1, 42, 3]
# --- Set by slice ---
lst_set_slice = lst.set(slice(1, 3), [7, 8])
assert list(lst_set_slice) == [1, 7, 8]
# --- Reverse ---
lst_rev = lst.reverse()
assert list(lst_rev) == [3, 2, 1]
# --- Pop ---
lst_popped, val = lst.pop()
assert list(lst_popped) == [1, 2]
assert val == 3
# --- Clear ---
lst_clear = lst.clear()
assert list(lst_clear) == []
assert lst_clear == COWList()
# --- Repr ---
assert repr(lst) == 'COWList([1, 2, 3])'
# --- Contains ---
assert 2 in lst
assert 5 not in lst
# --- Comparison ---
assert COWList([1, 2]) < COWList([1, 2, 3])
assert COWList([1, 3]) > COWList([1, 2])
How It Works
Internally, COWList maintains:
- A shared physical list of elements.
- A logical offset CanonicalRange into that list.
On mutation, if possible, it reuses storage; otherwise, it copies only the parts it needs.
This strategy enables structural sharing and helps maintain immutability while preserving performance.
API Reference
| Method | Description |
|---|---|
__getitem__(self, index_or_slice: Union[int, slice]) -> Union[T, Self] |
Get element at index or sliced view of the list. O(1) |
append(self, value: T) -> Self |
Return new instance with value appended to the end. O(1) if current instance is contiguous, O(n) if current instance is a sliced view. |
extend(self, iterable: Iterable[T]) -> Self, __add__(self, iterable: Iterable[T]) -> Self |
Return new instance extended with values in iterable. O(k) if current instance is contiguous, O(n + k) if current instance is a sliced view. |
insert(self, index: int, value: T) -> Self |
Return new instance with value inserted at index. O(n) |
delete(self, index_or_slice: Union[int, slice]) -> Self |
Return new instance with element(s) at specified position(s) deleted. O(n) |
set(self, index_or_slice: Union[int, slice], value_or_iterable: Union[T, Iterable[T]]) -> Self |
Return new instance with element(s) at given position(s) replaced with new value(s). O(n) |
pop(self, index: int = -1) -> Tuple[Self, T] |
Return (new instance with item removed, removed item), where removed item is self[i]. O(n) |
clear(self) -> Self |
Return an empty new instance. O(1) |
reverse(self) -> Self |
Return a sliced view of the list with the elements in reverse order. O(1) |
Contributing
Contributions are welcome! Please submit pull requests or open issues on the GitHub repository.
License
This project is licensed under the Apache License.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cowlist-0.1.0a5.tar.gz.
File metadata
- Download URL: cowlist-0.1.0a5.tar.gz
- Upload date:
- Size: 10.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1869d52b855d8a95d2a64f60123a9e8b407713fec2002199396c85b85f3f9ce3
|
|
| MD5 |
a12ebeb28923f58b0e11cc1b308dcaff
|
|
| BLAKE2b-256 |
5a724ccc2c219ec82582425f3dc3c89dedab55783ecacc565aedb7ce97fa8401
|
File details
Details for the file cowlist-0.1.0a5-py2.py3-none-any.whl.
File metadata
- Download URL: cowlist-0.1.0a5-py2.py3-none-any.whl
- Upload date:
- Size: 11.5 kB
- Tags: Python 2, Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
595a7c604995e37df21966c86fc1e106e55a324cd7033f70fbca4853c80e3cd5
|
|
| MD5 |
a1d4a59d4b2cc47758cde006bc7e45e6
|
|
| BLAKE2b-256 |
776d0048f9f9aa3ac9cd068439ca6b516f7d810ab5502a4ecad171760ca5b64a
|