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.00
# FrozenList
1
2
A 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.
3
4
## Package Information
5
6
- **Package Name**: frozenlist
7
- **Language**: Python
8
- **Installation**: `pip install frozenlist`
9
10
## Core Imports
11
12
```python
13
from frozenlist import FrozenList
14
```
15
16
For explicit access to implementations:
17
18
```python
19
from frozenlist import PyFrozenList # Pure Python implementation
20
# CFrozenList is available as FrozenList when Cython extensions are loaded
21
```
22
23
Access to package constants:
24
25
```python
26
from frozenlist import __version__, __all__, NO_EXTENSIONS
27
```
28
29
## Basic Usage
30
31
```python
32
from frozenlist import FrozenList
33
34
# Create a new FrozenList
35
fl = FrozenList([1, 2, 3])
36
37
# Add items while mutable
38
fl.append(4)
39
fl.extend([5, 6])
40
fl.insert(0, 0)
41
print(fl) # <FrozenList(frozen=False, [0, 1, 2, 3, 4, 5, 6])>
42
43
# Check if frozen
44
print(fl.frozen) # False
45
46
# Freeze the list to make it immutable
47
fl.freeze()
48
print(fl.frozen) # True
49
50
# Now it's hashable and can be used as a dict key
51
data = {fl: "my frozen list"}
52
print(hash(fl)) # Works now
53
54
# Modifications now raise RuntimeError
55
try:
56
fl.append(7)
57
except RuntimeError as e:
58
print(e) # Cannot modify frozen list.
59
```
60
61
## Architecture
62
63
FrozenList provides dual implementations for optimal performance:
64
65
- **Python Implementation**: Pure Python fallback (`PyFrozenList`) always available
66
- **Cython Implementation**: High-performance version with atomic operations for thread-safe frozen state management
67
- **Automatic Selection**: Uses Cython version by default unless `FROZENLIST_NO_EXTENSIONS` environment variable is set
68
69
The design supports two distinct phases:
70
1. **Mutable Phase**: Full list functionality, supports all modification operations
71
2. **Frozen Phase**: Immutable state, becomes hashable and can be used as dict keys or set elements
72
73
## Capabilities
74
75
### Package Constants
76
77
```python { .api }
78
__version__: str
79
"""Package version string (currently "1.7.0")."""
80
81
__all__: tuple
82
"""Exported public API: ("FrozenList", "PyFrozenList")."""
83
84
NO_EXTENSIONS: bool
85
"""Boolean flag indicating if Cython extensions are disabled via FROZENLIST_NO_EXTENSIONS environment variable."""
86
```
87
88
### Core Construction and Control
89
90
```python { .api }
91
class FrozenList:
92
def __init__(self, items=None):
93
"""
94
Initialize FrozenList with optional items.
95
96
Parameters:
97
- items: Iterable, optional initial items (default: None)
98
"""
99
100
@property
101
def frozen(self) -> bool:
102
"""Check if the list is frozen (immutable)."""
103
104
def freeze(self) -> None:
105
"""
106
Freeze the list, making it immutable and hashable.
107
After calling this method, any modification attempts will raise RuntimeError.
108
"""
109
```
110
111
### Sequence Access Operations
112
113
```python { .api }
114
# Overloaded methods support both int and slice operations
115
@overload
116
def __getitem__(self, index: int) -> _T:
117
"""Get item by index."""
118
119
@overload
120
def __getitem__(self, index: slice) -> FrozenList[_T]:
121
"""Get items by slice."""
122
123
def __getitem__(self, index):
124
"""
125
Get item(s) by index or slice.
126
127
Parameters:
128
- index: int or slice, position(s) to access
129
130
Returns:
131
- _T: Item at index (when index is int)
132
- FrozenList[_T]: New FrozenList containing sliced items (when index is slice)
133
"""
134
135
@overload
136
def __setitem__(self, index: int, value: _T) -> None:
137
"""Set item by index."""
138
139
@overload
140
def __setitem__(self, index: slice, value: Iterable[_T]) -> None:
141
"""Set items by slice."""
142
143
def __setitem__(self, index, value):
144
"""
145
Set item(s) by index or slice.
146
147
Parameters:
148
- index: int or slice, position(s) to modify
149
- value: _T or Iterable[_T], new value(s)
150
151
Raises:
152
RuntimeError: If list is frozen
153
"""
154
155
@overload
156
def __delitem__(self, index: int) -> None:
157
"""Delete item by index."""
158
159
@overload
160
def __delitem__(self, index: slice) -> None:
161
"""Delete items by slice."""
162
163
def __delitem__(self, index):
164
"""
165
Delete item(s) by index or slice.
166
167
Parameters:
168
- index: int or slice, position(s) to delete
169
170
Raises:
171
RuntimeError: If list is frozen
172
"""
173
174
def __len__(self) -> int:
175
"""Return the number of items in the list."""
176
177
def __iter__(self):
178
"""Return an iterator over the list items."""
179
180
def __reversed__(self):
181
"""Return a reverse iterator over the list items."""
182
183
def __contains__(self, item) -> bool:
184
"""
185
Check if item is in the list.
186
187
Parameters:
188
- item: any, item to search for
189
190
Returns:
191
bool: True if item is found
192
"""
193
```
194
195
### List Modification Operations
196
197
```python { .api }
198
def insert(self, pos: int, item):
199
"""
200
Insert item at specified position.
201
202
Parameters:
203
- pos: int, position to insert at
204
- item: any, item to insert
205
206
Raises:
207
RuntimeError: If list is frozen
208
"""
209
210
def append(self, item):
211
"""
212
Append item to the end of the list.
213
214
Parameters:
215
- item: any, item to append
216
217
Raises:
218
RuntimeError: If list is frozen
219
"""
220
221
def extend(self, items):
222
"""
223
Extend list with items from an iterable.
224
225
Parameters:
226
- items: iterable, items to add
227
228
Raises:
229
RuntimeError: If list is frozen
230
"""
231
232
def remove(self, item):
233
"""
234
Remove first occurrence of item.
235
236
Parameters:
237
- item: any, item to remove
238
239
Raises:
240
RuntimeError: If list is frozen
241
ValueError: If item is not found
242
"""
243
244
def pop(self, index: int = -1):
245
"""
246
Remove and return item at index.
247
248
Parameters:
249
- index: int, position to remove (default: -1 for last item)
250
251
Returns:
252
Removed item
253
254
Raises:
255
RuntimeError: If list is frozen
256
IndexError: If index is out of range
257
"""
258
259
def clear(self):
260
"""
261
Remove all items from the list.
262
263
Raises:
264
RuntimeError: If list is frozen
265
"""
266
267
def reverse(self):
268
"""
269
Reverse the list in place.
270
271
Raises:
272
RuntimeError: If list is frozen
273
"""
274
275
def __iadd__(self, items):
276
"""
277
In-place addition (+=) operator.
278
279
Parameters:
280
- items: iterable, items to add
281
282
Returns:
283
self
284
285
Raises:
286
RuntimeError: If list is frozen
287
"""
288
```
289
290
### Search and Query Operations
291
292
```python { .api }
293
def index(self, item):
294
"""
295
Return index of first occurrence of item.
296
297
Parameters:
298
- item: any, item to find
299
300
Returns:
301
int: Index of item
302
303
Raises:
304
ValueError: If item is not found
305
"""
306
307
def count(self, item) -> int:
308
"""
309
Count occurrences of item in the list.
310
311
Parameters:
312
- item: any, item to count
313
314
Returns:
315
int: Number of occurrences
316
"""
317
```
318
319
### Comparison Operations
320
321
```python { .api }
322
def __eq__(self, other) -> bool:
323
"""
324
Test equality with another sequence.
325
326
Parameters:
327
- other: any, object to compare with
328
329
Returns:
330
bool: True if sequences are equal
331
"""
332
333
def __ne__(self, other) -> bool:
334
"""Not equal comparison."""
335
336
def __lt__(self, other) -> bool:
337
"""Less than comparison."""
338
339
def __le__(self, other) -> bool:
340
"""Less than or equal comparison."""
341
342
def __gt__(self, other) -> bool:
343
"""Greater than comparison."""
344
345
def __ge__(self, other) -> bool:
346
"""Greater than or equal comparison."""
347
```
348
349
### Hashing and Representation
350
351
```python { .api }
352
def __hash__(self) -> int:
353
"""
354
Return hash of the frozen list.
355
356
Returns:
357
int: Hash value based on tuple of items
358
359
Raises:
360
RuntimeError: If list is not frozen
361
"""
362
363
def __repr__(self) -> str:
364
"""
365
Return string representation showing frozen state and contents.
366
367
Returns:
368
str: Representation like '<FrozenList(frozen=True, [1, 2, 3])>'
369
"""
370
```
371
372
### Utility Operations
373
374
```python { .api }
375
def __deepcopy__(self, memo):
376
"""
377
Create a deep copy of the FrozenList.
378
379
Parameters:
380
- memo: dict, memoization dictionary for circular reference handling
381
382
Returns:
383
FrozenList: Deep copy with same frozen state
384
385
Note: Only available in Cython implementation (CFrozenList).
386
The Python implementation (PyFrozenList) does not include this method.
387
"""
388
```
389
390
## Types and Aliases
391
392
```python { .api }
393
# Type definitions (from typing module)
394
from typing import TypeVar, Generic, Iterable, Iterator, overload
395
396
_T = TypeVar("_T")
397
398
# Generic class definition
399
class FrozenList(Generic[_T]):
400
"""Generic FrozenList parameterized by type _T."""
401
402
# Implementation aliases
403
PyFrozenList = FrozenList
404
"""Explicit reference to pure Python implementation."""
405
406
# CFrozenList is available as FrozenList when Cython extensions are loaded
407
```
408
409
## Implementation Notes
410
411
### MutableSequence Interface
412
FrozenList implements the complete `collections.abc.MutableSequence` interface. The Cython implementation explicitly registers with `MutableSequence.register(FrozenList)`.
413
414
### Implementation Differences
415
416
**Cython Implementation (CFrozenList - default when available):**
417
- Uses atomic operations (`atomic[bint]`) for thread-safe frozen flag management
418
- Includes `__deepcopy__` method for deep copying with circular reference handling
419
- Implements comparison operations via `__richcmp__` method
420
- Includes internal optimization methods (`_check_frozen`, `_fast_len`)
421
422
**Python Implementation (PyFrozenList - fallback):**
423
- Uses simple boolean for frozen flag (not thread-safe)
424
- No `__deepcopy__` method - relies on standard copy.deepcopy behavior
425
- Implements individual comparison methods (`__eq__`, `__le__`, etc.)
426
- No internal optimization methods
427
428
### Generic Type Support
429
Both implementations support generic type hints via `__class_getitem__ = classmethod(types.GenericAlias)`.
430
431
## Error Handling
432
433
FrozenList raises the following exceptions:
434
435
- **RuntimeError**: Raised when attempting to modify a frozen list or hash an unfrozen list
436
- **Standard exceptions**: IndexError, ValueError, etc. are raised for standard list operations as expected
437
438
## Environment Variables
439
440
- **FROZENLIST_NO_EXTENSIONS**: Set to any non-empty value to force use of pure Python implementation instead of Cython accelerated version