Persistent/Functional/Immutable data structures for Python
npx @tessl/cli install tessl/pypi-pyrsistent@0.20.0A 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.
pip install pyrsistentimport pyrsistentCommon imports for working with specific data structures:
from pyrsistent import pmap, pvector, pset, freeze, thawFor type checking and records:
from pyrsistent import PRecord, PClass, fieldFor type annotations:
from typing import Union, Mapping, Iterable, Tuple, TypeVar, Any
KT = TypeVar('KT') # Key type
VT = TypeVar('VT') # Value type
T = TypeVar('T') # Element typefrom 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 mutablePyrsistent provides two main categories of persistent data structures:
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.
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.
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]: ...Runtime type validation for persistent collections with optional invariant checking. Provides CheckedPMap, CheckedPVector, and CheckedPSet with customizable type constraints and validation rules.
class CheckedPMap(PMap):
__key_type__: type
__value_type__: type
class CheckedPVector(PVector):
__type__: type
class CheckedPSet(PSet):
__type__: type
def optional(*types) -> tuple: ...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.
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': ...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.
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: ...