pyrsistent
Persistent immutable data structures for Python — provides immutable dict, list, set, and record types that return new modified copies instead of mutating in place. pyrsistent features: pmap() for immutable dict, pvector() for immutable list, pset() for immutable set, PRecord for typed immutable records, freeze()/thaw() for converting to/from mutable types, evolve() for efficient updates returning new structures, PVector O(log32 n) update, m()/v()/s() for literal constructors, CheckedPMap/CheckedPVector for validated types, and structural sharing for memory efficiency on copies.
Score Breakdown
⚙ Agent Friendliness
🔒 Security
Immutable data structures prevent accidental state mutation — reduces certain classes of security bugs. No network calls. freeze() of user-controlled nested structures performs deep traversal — not a security risk but may be slow for deeply nested untrusted data.
⚡ Reliability
Best When
Functional programming patterns requiring immutable state — agent state machines, history tracking, and config passing where accidental mutation causes bugs.
Avoid When
High-frequency in-place mutations, large mutable arrays, or when regular dict/list performance is sufficient.
Use Cases
- • Agent immutable config — from pyrsistent import pmap; config = pmap({'host': 'localhost', 'port': 5432, 'debug': False}); prod_config = config.set('debug', False).set('host', 'prod.db'); config['host'] — 'localhost' (unchanged) — immutable config prevents accidental mutation; agent passes config to worker functions safely; original unchanged after workers update it
- • Agent state machine — from pyrsistent import PRecord, field; class AgentState(PRecord): status = field(mandatory=True); memory = field(initial=pmap); next_state = current_state.set(status='running', memory=current_state.memory.set('key', 'value')) — typed immutable state records; agent state transitions always produce new state; old states preserved for rollback
- • Agent history/undo — from pyrsistent import pvector; history = pvector(); state = pmap({'count': 0}); history = history.append(state); state = state.set('count', 1); history = history.append(state); old_state = history[0] — immutable vector of states; agent undo/redo stores all states without copying; structural sharing makes storage efficient
- • Agent freeze nested structures — from pyrsistent import freeze, thaw; raw = {'a': [1, 2], 'b': {'c': 3}}; immutable = freeze(raw); mutable = thaw(immutable) — convert nested dicts/lists to pyrsistent types recursively; agent receives JSON config and freezes it; thaw() for converting back to regular Python for JSON serialization
- • Agent validated record — from pyrsistent import PRecord, field, CheckedPVector; class Point(PRecord): x = field(type=float, mandatory=True); y = field(type=float, mandatory=True); p = Point(x=1.0, y=2.0); invalid = Point(x='bad') — raises TypeError — typed immutable record; agent validates data at construction time; PRecord enforces types and required fields
Not For
- • High-frequency mutations — pyrsistent creates new objects on every change; for mutable collections with frequent updates use regular dict/list
- • Large flat lists — PVector O(log32 n) updates; for large flat arrays use list or numpy array
- • Thread-safe concurrent reads/writes — pyrsistent immutability prevents corruption but doesn't synchronize; for concurrent producers/consumers use queues
Interface
Authentication
No auth — pure Python data structure library.
Pricing
pyrsistent is MIT licensed. Free for all use.
Agent Metadata
Known Gotchas
- ⚠ set() creates new object, does not mutate — pm = pmap({'a': 1}); pm.set('b', 2) returns new pmap; pm['b'] still raises KeyError; agent code assigning result: pm = pm.set('b', 2); common mistake: calling set() without reassigning; debug with: print(pm) — shows original unchanged
- ⚠ evolve() is more efficient for multiple updates — pmap.set('a', 1).set('b', 2).set('c', 3) creates 3 intermediate objects; from pyrsistent import evolve; evolve(pm, a=1, b=2, c=3) creates only 1 new object; agent code with many simultaneous updates should prefer evolve()
- ⚠ PRecord fields require explicit defaults — PRecord field without initial= is mandatory; PRecord field without type= accepts any type; field(initial=pmap) creates fresh pmap per instance (not shared); agent code: class State(PRecord): items = field(initial=pvector) — lambda ensures new pvector per instance
- ⚠ freeze() only handles basic Python types — freeze({'a': datetime.now()}) raises TypeError because datetime is not a supported type; agent code with custom objects must convert before freeze(); freeze handles: dict, list, set, tuple, and primitives; use thaw() to convert back for JSON/pickle
- ⚠ pset() is unordered like set() — pset([3, 1, 2]) has no guaranteed iteration order; agent code expecting sorted output must: sorted(pset(items)); pset.add() returns new pset with element; pset is useful for immutable membership testing but not ordered iteration
- ⚠ PRecord does not support __slots__ optimization — PRecord instances have __dict__ like regular objects; for thousands of agent state instances, memory usage is similar to dict-based classes; for large-scale agent fleets with memory constraints, consider attrs/dataclasses with slots=True instead
Alternatives
Full Evaluation Report
Comprehensive deep-dive: security analysis, reliability audit, agent experience review, cost modeling, competitive positioning, and improvement roadmap for pyrsistent.
AI-powered analysis · PDF + markdown · Delivered within 30 minutes
Package Brief
Quick verdict, integration guide, cost projections, gotchas with workarounds, and alternatives comparison.
Delivered within 10 minutes
Score Monitoring
Get alerted when this package's AF, security, or reliability scores change significantly. Stay ahead of regressions.
Continuous monitoring
Scores are editorial opinions as of 2026-03-06.