145 lines
5 KiB
Markdown
145 lines
5 KiB
Markdown
|
|
# Pyrsistent
|
||
|
|
|
||
|
|
A comprehensive Python library providing persistent/immutable data structures. Pyrsistent enables functional programming patterns by offering immutable alternatives to Python's built-in collections (dict, list, set) that never modify in-place but return new instances with requested changes, enabling safer concurrent programming and easier reasoning about program state.
|
||
|
|
|
||
|
|
## Package Information
|
||
|
|
|
||
|
|
- **Package Name**: pyrsistent
|
||
|
|
- **Language**: Python
|
||
|
|
- **Installation**: `pip install pyrsistent`
|
||
|
|
|
||
|
|
## Core Imports
|
||
|
|
|
||
|
|
```python
|
||
|
|
import pyrsistent
|
||
|
|
```
|
||
|
|
|
||
|
|
Common imports for working with specific data structures:
|
||
|
|
|
||
|
|
```python
|
||
|
|
from pyrsistent import pmap, pvector, pset, freeze, thaw
|
||
|
|
```
|
||
|
|
|
||
|
|
For type checking and records:
|
||
|
|
|
||
|
|
```python
|
||
|
|
from pyrsistent import PRecord, PClass, field
|
||
|
|
```
|
||
|
|
|
||
|
|
For type annotations:
|
||
|
|
|
||
|
|
```python
|
||
|
|
from typing import Union, Mapping, Iterable, Tuple, TypeVar, Any
|
||
|
|
KT = TypeVar('KT') # Key type
|
||
|
|
VT = TypeVar('VT') # Value type
|
||
|
|
T = TypeVar('T') # Element type
|
||
|
|
```
|
||
|
|
|
||
|
|
## Basic Usage
|
||
|
|
|
||
|
|
```python
|
||
|
|
from pyrsistent import pmap, pvector, pset, freeze, thaw
|
||
|
|
|
||
|
|
# Create persistent collections
|
||
|
|
pm = pmap({'name': 'John', 'age': 30})
|
||
|
|
pv = pvector([1, 2, 3, 4, 5])
|
||
|
|
ps = pset([1, 2, 3, 3, 4]) # Duplicate 3 is automatically removed
|
||
|
|
|
||
|
|
# All operations return new instances
|
||
|
|
pm2 = pm.set('age', 31) # pm is unchanged
|
||
|
|
pv2 = pv.append(6) # pv is unchanged
|
||
|
|
ps2 = ps.add(5) # ps is unchanged
|
||
|
|
|
||
|
|
print(pm2) # pmap({'name': 'John', 'age': 31})
|
||
|
|
print(pv2) # pvector([1, 2, 3, 4, 5, 6])
|
||
|
|
print(ps2) # pset([1, 2, 3, 4, 5])
|
||
|
|
|
||
|
|
# Convert between mutable and immutable
|
||
|
|
regular_dict = {'a': 1, 'b': [2, 3], 'c': {4, 5}}
|
||
|
|
persistent = freeze(regular_dict) # Recursively converts to persistent
|
||
|
|
mutable = thaw(persistent) # Recursively converts back to mutable
|
||
|
|
```
|
||
|
|
|
||
|
|
## Architecture
|
||
|
|
|
||
|
|
Pyrsistent provides two main categories of persistent data structures:
|
||
|
|
|
||
|
|
- **Core Collections**: Immutable versions of Python's built-in collections with structural sharing for memory efficiency
|
||
|
|
- **Type-Checked Collections**: Enhanced versions with runtime type validation and invariant checking
|
||
|
|
- **Record Types**: Fixed-schema data structures for structured data modeling
|
||
|
|
|
||
|
|
All collections use structural sharing through Hash Array Mapped Tries (HAMT) and similar data structures, enabling O(log32 n) performance for most operations while minimizing memory usage.
|
||
|
|
|
||
|
|
## Capabilities
|
||
|
|
|
||
|
|
### Core Persistent Collections
|
||
|
|
|
||
|
|
Immutable alternatives to Python's built-in collections including persistent map (dict), vector (list), set, bag (multiset), list (linked), and deque (double-ended queue). All operations return new instances with structural sharing for efficiency.
|
||
|
|
|
||
|
|
```python { .api }
|
||
|
|
def pmap(initial: Union[Mapping[KT, VT], Iterable[Tuple[KT, VT]]] = {}, pre_size: int = 0) -> PMap[KT, VT]: ...
|
||
|
|
def pvector(iterable: Iterable[T] = ()) -> PVector[T]: ...
|
||
|
|
def pset(iterable: Iterable[T] = (), pre_size: int = 8) -> PSet[T]: ...
|
||
|
|
def pbag(elements: Iterable[T]) -> PBag[T]: ...
|
||
|
|
def plist(iterable: Iterable[T] = (), reverse: bool = False) -> PList[T]: ...
|
||
|
|
def pdeque(iterable: Iterable[T] = None, maxlen: int = None) -> PDeque[T]: ...
|
||
|
|
```
|
||
|
|
|
||
|
|
[Core Collections](./core-collections.md)
|
||
|
|
|
||
|
|
### Type-Checked Collections
|
||
|
|
|
||
|
|
Runtime type validation for persistent collections with optional invariant checking. Provides CheckedPMap, CheckedPVector, and CheckedPSet with customizable type constraints and validation rules.
|
||
|
|
|
||
|
|
```python { .api }
|
||
|
|
class CheckedPMap(PMap):
|
||
|
|
__key_type__: type
|
||
|
|
__value_type__: type
|
||
|
|
|
||
|
|
class CheckedPVector(PVector):
|
||
|
|
__type__: type
|
||
|
|
|
||
|
|
class CheckedPSet(PSet):
|
||
|
|
__type__: type
|
||
|
|
|
||
|
|
def optional(*types) -> tuple: ...
|
||
|
|
```
|
||
|
|
|
||
|
|
[Type-Checked Collections](./type-checked-collections.md)
|
||
|
|
|
||
|
|
### Records and Classes
|
||
|
|
|
||
|
|
Structured data types with fixed schemas, type checking, and serialization support. PRecord provides a dict-like interface while PClass provides an object-like interface, both with field specifications and validation.
|
||
|
|
|
||
|
|
```python { .api }
|
||
|
|
class PRecord(PMap):
|
||
|
|
def set(self, *args, **kwargs) -> 'PRecord': ...
|
||
|
|
@classmethod
|
||
|
|
def create(cls, kwargs: dict, ignore_extra: bool = False) -> 'PRecord': ...
|
||
|
|
def serialize(self, format=None) -> dict: ...
|
||
|
|
|
||
|
|
class PClass:
|
||
|
|
def set(self, *args, **kwargs) -> 'PClass': ...
|
||
|
|
@classmethod
|
||
|
|
def create(cls, kwargs: dict, ignore_extra: bool = False) -> 'PClass': ...
|
||
|
|
def serialize(self, format=None) -> dict: ...
|
||
|
|
|
||
|
|
def field(type=(), invariant=..., initial=..., mandatory: bool = False, factory=..., serializer=...) -> 'PField': ...
|
||
|
|
```
|
||
|
|
|
||
|
|
[Records and Classes](./records-and-classes.md)
|
||
|
|
|
||
|
|
### Utilities and Transformations
|
||
|
|
|
||
|
|
Helper functions for converting between mutable and immutable structures, applying transformations, and accessing nested data. Includes freeze/thaw conversion, transformation functions, and nested access utilities.
|
||
|
|
|
||
|
|
```python { .api }
|
||
|
|
def freeze(obj, strict: bool = True): ...
|
||
|
|
def thaw(obj, strict: bool = True): ...
|
||
|
|
def mutant(fn) -> callable: ...
|
||
|
|
def get_in(keys: Iterable, coll: Mapping, default=None, no_default: bool = False): ...
|
||
|
|
def inc(x: int) -> int: ...
|
||
|
|
def discard(evolver, key) -> None: ...
|
||
|
|
```
|
||
|
|
|
||
|
|
[Utilities and Transformations](./utilities.md)
|