Install & Compatibility
Where this runs
tested against v0.20.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.95 runs
installs and imports cleanly · install 0.0s · import 0.048s · 18.2MB
glibcpy 3.10–3.95 runs
installs and imports cleanly · install 1.8s · import 0.050s · 19MB
16MB installed
● package 16MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
PVector
✓ from pyrsistent import PVector
For persistent lists; also commonly imported via the 'v' factory function: `from pyrsistent import v`
PMap
✓ from pyrsistent import PMap
For persistent dictionaries; also commonly imported via the 'm' factory function: `from pyrsistent import m`
PSet
✓ from pyrsistent import PSet
For persistent sets; also commonly imported via the 's' factory function: `from pyrsistent import s`
PRecord
✓ from pyrsistent import PRecord
For immutable objects with fixed fields, similar to named tuples but with PMap capabilities.
freeze
✓ from pyrsistent import freeze
Recursively converts mutable Python collections to their pyrsistent counterparts.
thaw
✓ from pyrsistent import thaw
Recursively converts pyrsistent collections back to mutable Python collections.
This quickstart demonstrates the creation and immutable 'evolution' of `PVector` (list-like), `PMap` (dict-like), and `PRecord` (object-like) instances. Operations like `append`, `set`, or `discard` always return a new instance with the changes, ensuring the original data structure's integrity.
from pyrsistent import pvector, pmap, PRecord
# Create a persistent vector (list-like)
v1 = pvector([1, 2, 3])
v2 = v1.append(4) # Returns a new pvector, v1 remains unchanged
v3 = v2.set(1, 5) # Replaces element at index 1
print(f"Original vector: {v1}") # Expected: pvector([1, 2, 3])
print(f"Appended vector: {v2}") # Expected: pvector([1, 2, 3, 4])
print(f"Modified vector: {v3}") # Expected: pvector([1, 5, 3, 4])
# Create a persistent map (dict-like)
m1 = pmap({'a': 1, 'b': 2})
m2 = m1.set('c', 3) # Returns a new pmap, m1 remains unchanged
m3 = m2.set('a', 5) # Updates value for key 'a'
print(f"Original map: {m1}") # Expected: pmap({'a': 1, 'b': 2})
print(f"Appended map: {m2}") # Expected: pmap({'a': 1, 'b': 2, 'c': 3})
print(f"Modified map: {m3}") # Expected: pmap({'a': 5, 'b': 2, 'c': 3})
# Define a persistent record
class User(PRecord):
name = None
age = None
user1 = User(name='Alice', age=30)
user2 = user1.set(age=31) # Returns a new User record
print(f"Original user: {user1}") # Expected: User(name='Alice', age=30)
print(f"Updated user: {user2}") # Expected: User(name='Alice', age=31)
Debug
Known issues
breakingThe behavior of `freeze` and `thaw` functions changed in a past update (related to issue #209). They now recursively convert `pyrsistent` data structures into Python built-in types and vice-versa. To retain the *old* (less recursive) behavior, you must explicitly pass `strict=False`.fixReview calls to `freeze()` and `thaw()`. If deep recursion is undesired, pass `strict=False` (e.g., `freeze(my_pyrsistent_obj, strict=False)`).
affects: <=0.20.0 (change was introduced prior to 0.20.0, affects users migrating from older versions)
breakingThe behavior of `PMap.remove()` was changed in version 0.7.0. It now raises a `KeyError` if the element to be removed is not present. The `PMap.discard()` method was introduced as an alternative that returns the original `PMap` instance if the element is not found, aligning with `PSet`'s behavior.fixReplace `PMap.remove(key)` with `PMap.discard(key)` if you want to avoid `KeyError` when a key might not exist, or ensure you handle the `KeyError` if `remove` is used.
affects: >=0.7.0
breakingThe methods `PMap.merge()` and `PMap.merge_with()` were deprecated and subsequently removed. They were renamed to `PMap.update()` and `PMap.update_with()` respectively.fixReplace calls to `merge()` with `update()` and `merge_with()` with `update_with()`.
affects: <1.0 (deprecated before 0.6.3, removed by 1.0)
gotchaPyrsistent data structures are fundamentally immutable. Any method that appears to 'modify' a structure (e.g., `append`, `set`, `remove`) actually returns a *new* instance with the changes, leaving the original unchanged. Attempting to treat them as mutable will lead to unexpected results where the original object appears not to have changed.fixAlways assign the result of modification operations to a new variable or back to the original variable to capture the new state (e.g., `my_vec = my_vec.append(item)`). Understand that you are always creating new versions, not altering existing ones.
affects: All versions
gotchaFor scenarios requiring many sequential updates to a `pyrsistent` collection where intermediate states are not needed, using an 'Evolver' (`pvector.evolver()`, `pmap.evolver()`, `pset.evolver()`) can be more efficient. Evolvers provide a mutable view for temporary, batch updates before finalizing to a new persistent structure.fixWrap sequences of temporary mutations in an evolver: `with my_pvector.evolver() as e: e[idx] = val; e.append(item); new_pvector = e.persistent()`.
affects: All versions
gotchaPRecords require fields to be explicitly defined as part of their class definition. Attempting to initialize or set a field that was not declared will raise an `AttributeError`.fixEnsure all fields you intend to use with a `PRecord` are explicitly declared in its class definition using `field()` or `_fields`. For example: `class MyRecord(PRecord): name = field(); age = field()`.
affects: All versions
breakingPRecord instances must be initialized only with fields explicitly defined using `PRecord.field()` in the subclass. Passing keyword arguments for fields not declared in the `PRecord` definition will raise an `AttributeError`.fixEnsure that all fields intended to be set during `PRecord` instantiation are explicitly declared in the `PRecord` subclass using `PRecord.field()`. Alternatively, review the instantiation call to only pass declared fields.
affects: All versions
Errors
Common errors & fixes
TypeError: 'pvector' object does not support item assignment
Users attempt to modify a `pvector` in-place using item assignment (`pv[idx] = value`), which is not allowed because `pvector` is an immutable data structure.
fixUse the `set` method, which returns a new `pvector` with the updated value at the specified index. Example: `new_pv = pv.set(1, 10)`
TypeError: 'pmap' object does not support item assignment
Users attempt to modify a `pmap` in-place using item assignment (`pm[key] = value`), which is not allowed because `pmap` is an immutable data structure.
fixUse the `set` method, which returns a new `pmap` with the updated value for the specified key. Example: `new_pm = pm.set('b', 20)` AttributeError: 'pvector' object has no attribute 'append'
Users try to use mutable list methods like `append` in-place on a `pvector` object, which is immutable and returns new instances on modification.
fixUse the `append` method of `pvector`, which returns a new `pvector` with the added element. Example: `new_pv = pv.append(3)`
TypeError: 'pset' object is not subscriptable
Users attempt to access elements of a `pset` using indexing (`ps[index]`), which is not supported as sets are unordered and do not allow indexed access.
fixTo check for membership, use the `in` operator (e.g., `if value in ps:`). If indexed access is required, convert the `pset` to a list first (e.g., `list(ps)[0]`).
Upgrade
Version history
0.20.0latest on PyPI · released Oct 25, 2023
Audit
Dependencies
No dependency data recorded yet.