This release is a pre-release and may not be stable for production use.
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.
Release files for cowlist 0.1.0a5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| cowlist-0.1.0a5.tar.gz | 10.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| cowlist-0.1.0a5-py2.py3-none-any.whl | Python 2, Python 3 | none | any | Details |
Total release size: 22.4 kB
Release files / cowlist-0.1.0a5.tar.gz
| Download URL | cowlist-0.1.0a5.tar.gz |
|---|---|
| Size | 10.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1869d52b855d8a95d2a64f60123a9e8b407713fec2002199396c85b85f3f9ce3
|
|
BLAKE2b-256 checksum How to use checksums |
5a724ccc2c219ec82582425f3dc3c89dedab55783ecacc565aedb7ce97fa8401
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.2
|
Release files / cowlist-0.1.0a5-py2.py3-none-any.whl
| Download URL | cowlist-0.1.0a5-py2.py3-none-any.whl |
|---|---|
| Size | 11.5 kB |
| Tags | Python 2 Python 3 |
|
SHA-256 checksum How to use checksums |
595a7c604995e37df21966c86fc1e106e55a324cd7033f70fbca4853c80e3cd5
|
|
BLAKE2b-256 checksum How to use checksums |
776d0048f9f9aa3ac9cd068439ca6b516f7d810ab5502a4ecad171760ca5b64a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.2
|