A list-like structure which implements collections.abc.MutableSequence that can be frozen to become immutable and hashable
npx @tessl/cli install tessl/pypi-frozenlist@1.7.0A specialized list-like data structure that implements collections.abc.MutableSequence with a unique freezing mechanism. FrozenList allows normal list operations (append, insert, modify) while mutable, but becomes immutable and hashable after calling freeze(), making it ideal for scenarios requiring both mutable construction and immutable usage.
pip install frozenlistfrom frozenlist import FrozenListFor explicit access to implementations:
from frozenlist import PyFrozenList # Pure Python implementation
# CFrozenList is available as FrozenList when Cython extensions are loadedAccess to package constants:
from frozenlist import __version__, __all__, NO_EXTENSIONSfrom frozenlist import FrozenList
# Create a new FrozenList
fl = FrozenList([1, 2, 3])
# Add items while mutable
fl.append(4)
fl.extend([5, 6])
fl.insert(0, 0)
print(fl) # <FrozenList(frozen=False, [0, 1, 2, 3, 4, 5, 6])>
# Check if frozen
print(fl.frozen) # False
# Freeze the list to make it immutable
fl.freeze()
print(fl.frozen) # True
# Now it's hashable and can be used as a dict key
data = {fl: "my frozen list"}
print(hash(fl)) # Works now
# Modifications now raise RuntimeError
try:
fl.append(7)
except RuntimeError as e:
print(e) # Cannot modify frozen list.FrozenList provides dual implementations for optimal performance:
PyFrozenList) always availableFROZENLIST_NO_EXTENSIONS environment variable is setThe design supports two distinct phases:
__version__: str
"""Package version string (currently "1.7.0")."""
__all__: tuple
"""Exported public API: ("FrozenList", "PyFrozenList")."""
NO_EXTENSIONS: bool
"""Boolean flag indicating if Cython extensions are disabled via FROZENLIST_NO_EXTENSIONS environment variable."""class FrozenList:
def __init__(self, items=None):
"""
Initialize FrozenList with optional items.
Parameters:
- items: Iterable, optional initial items (default: None)
"""
@property
def frozen(self) -> bool:
"""Check if the list is frozen (immutable)."""
def freeze(self) -> None:
"""
Freeze the list, making it immutable and hashable.
After calling this method, any modification attempts will raise RuntimeError.
"""# Overloaded methods support both int and slice operations
@overload
def __getitem__(self, index: int) -> _T:
"""Get item by index."""
@overload
def __getitem__(self, index: slice) -> FrozenList[_T]:
"""Get items by slice."""
def __getitem__(self, index):
"""
Get item(s) by index or slice.
Parameters:
- index: int or slice, position(s) to access
Returns:
- _T: Item at index (when index is int)
- FrozenList[_T]: New FrozenList containing sliced items (when index is slice)
"""
@overload
def __setitem__(self, index: int, value: _T) -> None:
"""Set item by index."""
@overload
def __setitem__(self, index: slice, value: Iterable[_T]) -> None:
"""Set items by slice."""
def __setitem__(self, index, value):
"""
Set item(s) by index or slice.
Parameters:
- index: int or slice, position(s) to modify
- value: _T or Iterable[_T], new value(s)
Raises:
RuntimeError: If list is frozen
"""
@overload
def __delitem__(self, index: int) -> None:
"""Delete item by index."""
@overload
def __delitem__(self, index: slice) -> None:
"""Delete items by slice."""
def __delitem__(self, index):
"""
Delete item(s) by index or slice.
Parameters:
- index: int or slice, position(s) to delete
Raises:
RuntimeError: If list is frozen
"""
def __len__(self) -> int:
"""Return the number of items in the list."""
def __iter__(self):
"""Return an iterator over the list items."""
def __reversed__(self):
"""Return a reverse iterator over the list items."""
def __contains__(self, item) -> bool:
"""
Check if item is in the list.
Parameters:
- item: any, item to search for
Returns:
bool: True if item is found
"""def insert(self, pos: int, item):
"""
Insert item at specified position.
Parameters:
- pos: int, position to insert at
- item: any, item to insert
Raises:
RuntimeError: If list is frozen
"""
def append(self, item):
"""
Append item to the end of the list.
Parameters:
- item: any, item to append
Raises:
RuntimeError: If list is frozen
"""
def extend(self, items):
"""
Extend list with items from an iterable.
Parameters:
- items: iterable, items to add
Raises:
RuntimeError: If list is frozen
"""
def remove(self, item):
"""
Remove first occurrence of item.
Parameters:
- item: any, item to remove
Raises:
RuntimeError: If list is frozen
ValueError: If item is not found
"""
def pop(self, index: int = -1):
"""
Remove and return item at index.
Parameters:
- index: int, position to remove (default: -1 for last item)
Returns:
Removed item
Raises:
RuntimeError: If list is frozen
IndexError: If index is out of range
"""
def clear(self):
"""
Remove all items from the list.
Raises:
RuntimeError: If list is frozen
"""
def reverse(self):
"""
Reverse the list in place.
Raises:
RuntimeError: If list is frozen
"""
def __iadd__(self, items):
"""
In-place addition (+=) operator.
Parameters:
- items: iterable, items to add
Returns:
self
Raises:
RuntimeError: If list is frozen
"""def index(self, item):
"""
Return index of first occurrence of item.
Parameters:
- item: any, item to find
Returns:
int: Index of item
Raises:
ValueError: If item is not found
"""
def count(self, item) -> int:
"""
Count occurrences of item in the list.
Parameters:
- item: any, item to count
Returns:
int: Number of occurrences
"""def __eq__(self, other) -> bool:
"""
Test equality with another sequence.
Parameters:
- other: any, object to compare with
Returns:
bool: True if sequences are equal
"""
def __ne__(self, other) -> bool:
"""Not equal comparison."""
def __lt__(self, other) -> bool:
"""Less than comparison."""
def __le__(self, other) -> bool:
"""Less than or equal comparison."""
def __gt__(self, other) -> bool:
"""Greater than comparison."""
def __ge__(self, other) -> bool:
"""Greater than or equal comparison."""def __hash__(self) -> int:
"""
Return hash of the frozen list.
Returns:
int: Hash value based on tuple of items
Raises:
RuntimeError: If list is not frozen
"""
def __repr__(self) -> str:
"""
Return string representation showing frozen state and contents.
Returns:
str: Representation like '<FrozenList(frozen=True, [1, 2, 3])>'
"""def __deepcopy__(self, memo):
"""
Create a deep copy of the FrozenList.
Parameters:
- memo: dict, memoization dictionary for circular reference handling
Returns:
FrozenList: Deep copy with same frozen state
Note: Only available in Cython implementation (CFrozenList).
The Python implementation (PyFrozenList) does not include this method.
"""# Type definitions (from typing module)
from typing import TypeVar, Generic, Iterable, Iterator, overload
_T = TypeVar("_T")
# Generic class definition
class FrozenList(Generic[_T]):
"""Generic FrozenList parameterized by type _T."""
# Implementation aliases
PyFrozenList = FrozenList
"""Explicit reference to pure Python implementation."""
# CFrozenList is available as FrozenList when Cython extensions are loadedFrozenList implements the complete collections.abc.MutableSequence interface. The Cython implementation explicitly registers with MutableSequence.register(FrozenList).
Cython Implementation (CFrozenList - default when available):
atomic[bint]) for thread-safe frozen flag management__deepcopy__ method for deep copying with circular reference handling__richcmp__ method_check_frozen, _fast_len)Python Implementation (PyFrozenList - fallback):
__deepcopy__ method - relies on standard copy.deepcopy behavior__eq__, __le__, etc.)Both implementations support generic type hints via __class_getitem__ = classmethod(types.GenericAlias).
FrozenList raises the following exceptions: