API documentation

pmap(initial={}, pre_size=0)

Create new persistent map, inserts all elements in initial into the newly created map. The optional argument pre_size may be used to specify an initial size of the underlying bucket vector. This may have a positive performance impact in the cases where you know beforehand that a large number of elements will be inserted into the map eventually since it will reduce the number of reallocations required.

>>> pmap({'a': 13, 'b': 14})
pmap({'a': 13, 'b': 14})
m(**kwargs)

Creates a new persitent map. Inserts all key value arguments into the newly created map.

>>> m(a=13, b=14)
pmap({'a': 13, 'b': 14})
class PMap

Persistent map/dict. Tries to follow the same naming conventions as the built in dict where feasible.

Do not instantiate directly, instead use the factory functions m() or pmap() to create an instance.

Was originally written as a very close copy of the Clojure equivalent but was later rewritten to closer re-assemble the python dict. This means that a sparse vector (a PVector) of buckets is used. The keys are hashed and the elements inserted at position hash % len(bucket_vector). Whenever the map size exceeds 2/3 of the containing vectors size the map is reallocated to a vector of double the size. This is done to avoid excessive hash collisions.

This structure corresponds most closely to the built in dict type and is intended as a replacement. Where the semantics are the same (more or less) the same function names have been used but for some cases it is not possible, for example assignments and deletion of values.

PMap implements the Mapping protocol and is Hashable.

Random access and insert is log32(n) where n is the size of the map.

The following are examples of some common operations on persistent maps

>>> m1 = m(a=1, b=3)
>>> m2 = m1.set('c', 3)
>>> m3 = m2.remove('a')
>>> m1
pmap({'a': 1, 'b': 3})
>>> m2
pmap({'a': 1, 'c': 3, 'b': 3})
>>> m3
pmap({'c': 3, 'b': 3})
>>> m3['c']
3
discard(key)

Return a new PMap without the element specified by key. Returns reference to itself if element is not present.

>>> m1 = m(a=1, b=2)
>>> m1.discard('a')
pmap({'b': 2})
>>> m1 is m1.discard('c')
True
evolver()

Create a new evolver for this pmap. For a discussion on evolvers in general see the documentation for the pvector evolver.

Create the evolver and perform various mutating updates to it:

>>> m1 = m(a=1, b=2)
>>> e = m1.evolver()
>>> e['c'] = 3
>>> len(e)
3
>>> del e['a']

The underlying pmap remains the same:

>>> m1
pmap({'a': 1, 'b': 2})

The changes are kept in the evolver. An updated pmap can be created using the persistent() function on the evolver.

>>> m2 = e.persistent()
>>> m2
pmap({'c': 3, 'b': 2})

The new pmap will share data with the original pmap in the same way that would have been done if only using operations on the pmap.

get(k[, d]) → D[k] if k in D, else d. d defaults to None.
remove(key)

Return a new PMap without the element specified by key. Raises KeyError if the element is not present.

>>> m1 = m(a=1, b=2)
>>> m1.remove('a')
pmap({'b': 2})
set(key, val)

Return a new PMap with key and val inserted.

>>> m1 = m(a=1, b=2)
>>> m2 = m1.set('a', 3)
>>> m3 = m1.set('c' ,4)
>>> m1
pmap({'a': 1, 'b': 2})
>>> m2
pmap({'a': 3, 'b': 2})
>>> m3
pmap({'a': 1, 'c': 4, 'b': 2})
transform(*transformations)

Transform arbitrarily complex combinations of PVectors and PMaps. A transformation consists of two parts. One match expression that specifies which elements to transform and one transformation function that performs the actual transformation.

>>> from pyrsistent import freeze, ny
>>> news_paper = freeze({'articles': [{'author': 'Sara', 'content': 'A short article'},
...                                   {'author': 'Steve', 'content': 'A slightly longer article'}],
...                      'weather': {'temperature': '11C', 'wind': '5m/s'}})
>>> short_news = news_paper.transform(['articles', ny, 'content'], lambda c: c[:25] + '...' if len(c) > 25 else c)
>>> very_short_news = news_paper.transform(['articles', ny, 'content'], lambda c: c[:15] + '...' if len(c) > 15 else c)
>>> very_short_news.articles[0].content
'A short article'
>>> very_short_news.articles[1].content
'A slightly long...'

When nothing has been transformed the original data structure is kept

>>> short_news is news_paper
True
>>> very_short_news is news_paper
False
>>> very_short_news.articles[0] is news_paper.articles[0]
True
update(*maps)

Return a new PMap with the items in Mappings inserted. If the same key is present in multiple maps the rightmost (last) value is inserted.

>>> m1 = m(a=1, b=2)
>>> m1.update(m(a=2, c=3), {'a': 17, 'd': 35})
pmap({'a': 17, 'c': 3, 'b': 2, 'd': 35})
update_with(update_fn, *maps)

Return a new PMap with the items in Mappings maps inserted. If the same key is present in multiple maps the values will be merged using merge_fn going from left to right.

>>> from operator import add
>>> m1 = m(a=1, b=2)
>>> m1.update_with(add, m(a=2))
pmap({'a': 3, 'b': 2})

The reverse behaviour of the regular merge. Keep the leftmost element instead of the rightmost.

>>> m1 = m(a=1)
>>> m1.update_with(lambda l, r: l, m(a=2), {'a':3})
pmap({'a': 1})
pvector([iterable])

Create a new persistent vector containing the elements in iterable.

>>> v1 = pvector([1, 2, 3])
>>> v1
pvector([1, 2, 3])
v(*elements)

Create a new persistent vector containing all parameters to this function.

>>> v1 = v(1, 2, 3)
>>> v1
pvector([1, 2, 3])
class PVector

Persistent vector implementation. Meant as a replacement for the cases where you would normally use a Python list.

Do not instantiate directly, instead use the factory functions v() and pvector() to create an instance.

Heavily influenced by the persistent vector available in Clojure. Initially this was more or less just a port of the Java code for the Clojure vector. It has since been modified and to some extent optimized for usage in Python.

The vector is organized as a trie, any mutating method will return a new vector that contains the changes. No updates are done to the original vector. Structural sharing between vectors are applied where possible to save space and to avoid making complete copies.

This structure corresponds most closely to the built in list type and is intended as a replacement. Where the semantics are the same (more or less) the same function names have been used but for some cases it is not possible, for example assignments.

The PVector implements the Sequence protocol and is Hashable.

Inserts are amortized O(1). Random access is log32(n) where n is the size of the vector.

The following are examples of some common operations on persistent vectors:

>>> p = v(1, 2, 3)
>>> p2 = p.append(4)
>>> p3 = p2.extend([5, 6, 7])
>>> p
pvector([1, 2, 3])
>>> p2
pvector([1, 2, 3, 4])
>>> p3
pvector([1, 2, 3, 4, 5, 6, 7])
>>> p3[5]
6
>>> p.set(1, 99)
pvector([1, 99, 3])
>>>
append(val)

Return a new vector with val appended.

>>> v1 = v(1, 2)
>>> v1.append(3)
pvector([1, 2, 3])
count(value)

Return the number of times that value appears in the vector.

>>> v1 = v(1, 4, 3, 4)
>>> v1.count(4)
2
delete(index, stop=None)

Delete a portion of the vector by index or range.

>>> v1 = v(1, 2, 3, 4, 5)
>>> v1.delete(1)
pvector([1, 3, 4, 5])
>>> v1.delete(1, 3)
pvector([1, 4, 5])
evolver()

Create a new evolver for this pvector. The evolver acts as a mutable view of the vector with “transaction like” semantics. No part of the underlying vector i updated, it is still fully immutable. Furthermore multiple evolvers created from the same pvector do not interfere with each other.

You may want to use an evolver instead of working directly with the pvector in the following cases:

  • Multiple updates are done to the same vector and the intermediate results are of no interest. In this case using an evolver may be a more efficient and easier to work with.
  • You need to pass a vector into a legacy function or a function that you have no control over which performs in place mutations of lists. In this case pass an evolver instance instead and then create a new pvector from the evolver once the function returns.

The following example illustrates a typical workflow when working with evolvers. It also displays most of the API (which i kept small by design, you should not be tempted to use evolvers in excess ;-)).

Create the evolver and perform various mutating updates to it:

>>> v1 = v(1, 2, 3, 4, 5)
>>> e = v1.evolver()
>>> e[1] = 22
>>> _ = e.append(6)
>>> _ = e.extend([7, 8, 9])
>>> e[8] += 1
>>> len(e)
9

The underlying pvector remains the same:

>>> v1
pvector([1, 2, 3, 4, 5])

The changes are kept in the evolver. An updated pvector can be created using the persistent() function on the evolver.

>>> v2 = e.persistent()
>>> v2
pvector([1, 22, 3, 4, 5, 6, 7, 8, 10])

The new pvector will share data with the original pvector in the same way that would have been done if only using operations on the pvector.

extend(obj)

Return a new vector with all values in obj appended to it. Obj may be another PVector or any other Iterable.

>>> v1 = v(1, 2, 3)
>>> v1.extend([4, 5])
pvector([1, 2, 3, 4, 5])
index(value, *args, **kwargs)

Return first index of value. Additional indexes may be supplied to limit the search to a sub range of the vector.

>>> v1 = v(1, 2, 3, 4, 3)
>>> v1.index(3)
2
>>> v1.index(3, 3, 5)
4
mset(*args)

Return a new vector with elements in specified positions replaced by values (multi set).

Elements on even positions in the argument list are interpreted as indexes while elements on odd positions are considered values.

>>> v1 = v(1, 2, 3)
>>> v1.mset(0, 11, 2, 33)
pvector([11, 2, 33])
remove(value)

Remove the first occurrence of a value from the vector.

>>> v1 = v(1, 2, 3, 2, 1)
>>> v2 = v1.remove(1)
>>> v2
pvector([2, 3, 2, 1])
>>> v2.remove(1)
pvector([2, 3, 2])
set(i, val)

Return a new vector with element at position i replaced with val. The original vector remains unchanged.

Setting a value one step beyond the end of the vector is equal to appending. Setting beyond that will result in an IndexError.

>>> v1 = v(1, 2, 3)
>>> v1.set(1, 4)
pvector([1, 4, 3])
>>> v1.set(3, 4)
pvector([1, 2, 3, 4])
>>> v1.set(-1, 4)
pvector([1, 2, 4])
transform(*transformations)

Transform arbitrarily complex combinations of PVectors and PMaps. A transformation consists of two parts. One match expression that specifies which elements to transform and one transformation function that performs the actual transformation.

>>> from pyrsistent import freeze, ny
>>> news_paper = freeze({'articles': [{'author': 'Sara', 'content': 'A short article'},
...                                   {'author': 'Steve', 'content': 'A slightly longer article'}],
...                      'weather': {'temperature': '11C', 'wind': '5m/s'}})
>>> short_news = news_paper.transform(['articles', ny, 'content'], lambda c: c[:25] + '...' if len(c) > 25 else c)
>>> very_short_news = news_paper.transform(['articles', ny, 'content'], lambda c: c[:15] + '...' if len(c) > 15 else c)
>>> very_short_news.articles[0].content
'A short article'
>>> very_short_news.articles[1].content
'A slightly long...'

When nothing has been transformed the original data structure is kept

>>> short_news is news_paper
True
>>> very_short_news is news_paper
False
>>> very_short_news.articles[0] is news_paper.articles[0]
True
pset(iterable=(), pre_size=8)

Creates a persistent set from iterable. Optionally takes a sizing parameter equivalent to that used for pmap().

>>> s1 = pset([1, 2, 3, 2])
>>> s1
pset([1, 2, 3])
s(*elements)

Create a persistent set.

Takes an arbitrary number of arguments to insert into the new set.

>>> s1 = s(1, 2, 3, 2)
>>> s1
pset([1, 2, 3])
class PSet

Persistent set implementation. Built on top of the persistent map. The set supports all operations in the Set protocol and is Hashable.

Do not instantiate directly, instead use the factory functions s() or pset() to create an instance.

Random access and insert is log32(n) where n is the size of the set.

Some examples:

>>> s = pset([1, 2, 3, 1])
>>> s2 = s.add(4)
>>> s3 = s2.remove(2)
>>> s
pset([1, 2, 3])
>>> s2
pset([1, 2, 3, 4])
>>> s3
pset([1, 3, 4])
add(element)

Return a new PSet with element added

>>> s1 = s(1, 2)
>>> s1.add(3)
pset([1, 2, 3])
discard(element)

Return a new PSet with element removed. Returns itself if element is not present.

evolver()

Create a new evolver for this pset. For a discussion on evolvers in general see the documentation for the pvector evolver.

Create the evolver and perform various mutating updates to it:

>>> s1 = s(1, 2, 3)
>>> e = s1.evolver()
>>> _ = e.add(4)
>>> len(e)
4
>>> _ = e.remove(1)

The underlying pset remains the same:

>>> s1
pset([1, 2, 3])

The changes are kept in the evolver. An updated pmap can be created using the persistent() function on the evolver.

>>> s2 = e.persistent()
>>> s2
pset([2, 3, 4])

The new pset will share data with the original pset in the same way that would have been done if only using operations on the pset.

isdisjoint(other)

Return True if two sets have a null intersection.

remove(element)

Return a new PSet with element removed. Raises KeyError if element is not present.

>>> s1 = s(1, 2)
>>> s1.remove(2)
pset([1])
update(iterable)

Return a new PSet with elements in iterable added

>>> s1 = s(1, 2)
>>> s1.update([3, 4, 4])
pset([1, 2, 3, 4])
pbag(elements)

Convert an iterable to a persistent bag.

Takes an iterable with elements to insert.

>>> pbag([1, 2, 3, 2])
pbag([1, 2, 2, 3])
b(*elements)

Construct a persistent bag.

Takes an arbitrary number of arguments to insert into the new persistent bag.

>>> b(1, 2, 3, 2)
pbag([1, 2, 2, 3])
class PBag(counts)

A persistent bag/multiset type.

Requires elements to be hashable, and allows duplicates, but has no ordering. Bags are hashable.

Do not instantiate directly, instead use the factory functions b() or pbag() to create an instance.

Some examples:

>>> s = pbag([1, 2, 3, 1])
>>> s2 = s.add(4)
>>> s3 = s2.remove(1)
>>> s
pbag([1, 1, 2, 3])
>>> s2
pbag([1, 1, 2, 3, 4])
>>> s3
pbag([1, 2, 3, 4])
add(element)

Add an element to the bag.

>>> s = pbag([1])
>>> s2 = s.add(1)
>>> s3 = s.add(2)
>>> s2
pbag([1, 1])
>>> s3
pbag([1, 2])
count(element)

Return the number of times an element appears.

>>> pbag([]).count('non-existent')
0
>>> pbag([1, 1, 2]).count(1)
2
remove(element)

Remove an element from the bag.

>>> s = pbag([1, 1, 2])
>>> s2 = s.remove(1)
>>> s3 = s.remove(2)
>>> s2
pbag([1, 2])
>>> s3
pbag([1, 1])
update(iterable)

Update bag with all elements in iterable.

>>> s = pbag([1])
>>> s.update([1, 2])
pbag([1, 1, 2])
plist(iterable=(), reverse=False)

Creates a new persistent list containing all elements of iterable. Optional parameter reverse specifies if the elements should be inserted in reverse order or not.

>>> plist([1, 2, 3])
plist([1, 2, 3])
>>> plist([1, 2, 3], reverse=True)
plist([3, 2, 1])
l(*elements)

Creates a new persistent list containing all arguments.

>>> l(1, 2, 3)
plist([1, 2, 3])
class PList

Classical Lisp style singly linked list. Adding elements to the head using cons is O(1). Element access is O(k) where k is the position of the element in the list. Taking the length of the list is O(n).

Fully supports the Sequence and Hashable protocols including indexing and slicing but if you need fast random access go for the PVector instead.

Do not instantiate directly, instead use the factory functions l() or plist() to create an instance.

Some examples:

>>> x = plist([1, 2])
>>> y = x.cons(3)
>>> x
plist([1, 2])
>>> y
plist([3, 1, 2])
>>> y.first
3
>>> y.rest == x
True
>>> y[:2]
plist([3, 1])
pdeque(iterable=(), maxlen=None)

Return deque containing the elements of iterable. If maxlen is specified then len(iterable) - maxlen elements are discarded from the left to if len(iterable) > maxlen.

>>> pdeque([1, 2, 3])
pdeque([1, 2, 3])
>>> pdeque([1, 2, 3, 4], maxlen=2)
pdeque([3, 4], maxlen=2)
dq(*elements)

Return deque containing all arguments.

>>> dq(1, 2, 3)
pdeque([1, 2, 3])
class PDeque

Persistent double ended queue (deque). Allows quick appends and pops in both ends. Implemented using two persistent lists.

A maximum length can be specified to create a bounded queue.

Fully supports the Sequence and Hashable protocols including indexing and slicing but if you need fast random access go for the PVector instead.

Do not instantiate directly, instead use the factory functions dq() or pdeque() to create an instance.

Some examples:

>>> x = pdeque([1, 2, 3])
>>> x.left
1
>>> x.right
3
>>> x[0] == x.left
True
>>> x[-1] == x.right
True
>>> x.pop()
pdeque([1, 2])
>>> x.pop() == x[:-1]
True
>>> x.popleft()
pdeque([2, 3])
>>> x.append(4)
pdeque([1, 2, 3, 4])
>>> x.appendleft(4)
pdeque([4, 1, 2, 3])
>>> y = pdeque([1, 2, 3], maxlen=3)
>>> y.append(4)
pdeque([2, 3, 4], maxlen=3)
>>> y.appendleft(4)
pdeque([4, 1, 2], maxlen=3)
append(elem)

Return new deque with elem as the rightmost element.

>>> pdeque([1, 2]).append(3)
pdeque([1, 2, 3])
appendleft(elem)

Return new deque with elem as the leftmost element.

>>> pdeque([1, 2]).appendleft(3)
pdeque([3, 1, 2])
count(elem)

Return the number of elements equal to elem present in the queue

>>> pdeque([1, 2, 1]).count(1)
2
extend(iterable)

Return new deque with all elements of iterable appended to the right.

>>> pdeque([1, 2]).extend([3, 4])
pdeque([1, 2, 3, 4])
extendleft(iterable)

Return new deque with all elements of iterable appended to the left.

NB! The elements will be inserted in reverse order compared to the order in the iterable.

>>> pdeque([1, 2]).extendleft([3, 4])
pdeque([4, 3, 1, 2])
index(value) → integer -- return first index of value.

Raises ValueError if the value is not present.

left

Leftmost element in dqueue.

maxlen

Maximum length of the queue.

pop(count=1)

Return new deque with rightmost element removed. Popping the empty queue will return the empty queue. A optional count can be given to indicate the number of elements to pop. Popping with a negative index is the same as popleft. Executes in amortized O(k) where k is the number of elements to pop.

>>> pdeque([1, 2]).pop()
pdeque([1])
>>> pdeque([1, 2]).pop(2)
pdeque([])
>>> pdeque([1, 2]).pop(-1)
pdeque([2])
popleft(count=1)

Return new deque with leftmost element removed. Otherwise functionally equivalent to pop().

>>> pdeque([1, 2]).popleft()
pdeque([2])
remove(elem)

Return new deque with first element from left equal to elem removed. If no such element is found a ValueError is raised.

>>> pdeque([2, 1, 2]).remove(2)
pdeque([1, 2])
reverse()

Return reversed deque.

>>> pdeque([1, 2, 3]).reverse()
pdeque([3, 2, 1])

Also supports the standard python reverse function.

>>> reversed(pdeque([1, 2, 3]))
pdeque([3, 2, 1])
right

Rightmost element in dqueue.

rotate(steps)

Return deque with elements rotated steps steps.

>>> x = pdeque([1, 2, 3])
>>> x.rotate(1)
pdeque([3, 1, 2])
>>> x.rotate(-2)
pdeque([3, 1, 2])
class CheckedPMap

A CheckedPMap is a PMap which allows specifying type and invariant checks.

>>> class IntToFloatMap(CheckedPMap):
...     __key_type__ = int
...     __value_type__ = float
...     __invariant__ = lambda k, v: (int(v) == k, 'Invalid mapping')
...
>>> IntToFloatMap({1: 1.5, 2: 2.25})
IntToFloatMap({1: 1.5, 2: 2.25})
class CheckedPVector

A CheckedPVector is a PVector which allows specifying type and invariant checks.

>>> class Positives(CheckedPVector):
...     __type__ = (long, int)
...     __invariant__ = lambda n: (n >= 0, 'Negative')
...
>>> Positives([1, 2, 3])
Positives([1, 2, 3])
class CheckedPSet

A CheckedPSet is a PSet which allows specifying type and invariant checks.

>>> class Positives(CheckedPSet):
...     __type__ = (long, int)
...     __invariant__ = lambda n: (n >= 0, 'Negative')
...
>>> Positives([1, 2, 3])
Positives([1, 2, 3])
exception InvariantException(error_codes=(), missing_fields=(), *args, **kwargs)

Exception raised from a CheckedType when invariant tests fail or when a mandatory field is missing.

Contains two fields of interest: invariant_errors, a tuple of error data for the failing invariants missing_fields, a tuple of strings specifying the missing names

exception CheckedKeyTypeError(source_class, expected_types, actual_type, actual_value, *args, **kwargs)

Raised when trying to set a value using a key with a type that doesn’t match the declared type.

Attributes: source_class – The class of the collection expected_types – Allowed types actual_type – The non matching type actual_value – Value of the variable with the non matching type

exception CheckedValueTypeError(source_class, expected_types, actual_type, actual_value, *args, **kwargs)

Raised when trying to set a value using a key with a type that doesn’t match the declared type.

Attributes: source_class – The class of the collection expected_types – Allowed types actual_type – The non matching type actual_value – Value of the variable with the non matching type

class CheckedType

Marker class to enable creation and serialization of checked object graphs.

optional(*typs)

Convenience function to specify that a value may be of any of the types in type ‘typs’ or None

class PRecord

A PRecord is a PMap with a fixed set of specified fields. Records are declared as python classes inheriting from PRecord. Because it is a PMap it has full support for all Mapping methods such as iteration and element access using subscript notation.

More documentation and examples of PRecord usage is available at https://github.com/tobgu/pyrsistent

classmethod create(kwargs)

Factory method. Will create a new PRecord of the current type and assign the values specified in kwargs.

evolver()

Returns an evolver of this object.

serialize(format=None)

Serialize the current PRecord using custom serializer functions for fields where such have been supplied.

set(*args, **kwargs)

Set a field in the record. This set function differs slightly from that in the PMap class. First of all it accepts key-value pairs. Second it accepts multiple key-value pairs to perform one, atomic, update of multiple fields.

field(type=(), invariant=<function <lambda>>, initial=<object object>, mandatory=False, factory=<function <lambda>>, serializer=<function <lambda>>)

Field specification factory for PRecord.

Parameters:
  • type – a type or iterable with types that are allowed for this field
  • invariant – a function specifying an invariant that must hold for the field
  • initial – value of field if not specified when instantiating the record
  • mandatory – boolean specifying if the field is mandatory or not
  • factory – function called when field is set.
  • serializer – function that returns a serialized version of the field
pset_field(item_type, optional=False, initial=())

Create checked PSet field.

Parameters:
  • item_type – The required type for the items in the set.
  • optional – If true, None can be used as a value for this field.
  • initial – Initial value to pass to factory if no value is given for the field.
Returns:

A field containing a CheckedPSet of the given type.

pmap_field(key_type, value_type, optional=False, invariant=<function <lambda>>)

Create a checked PMap field.

Parameters:
  • key – The required type for the keys of the map.
  • value – The required type for the values of the map.
  • optional – If true, None can be used as a value for this field.
  • invariant – Pass-through to field.
Returns:

A field containing a CheckedPMap.

pvector_field(item_type, optional=False, initial=())

Create checked PVector field.

Parameters:
  • item_type – The required type for the items in the vector.
  • optional – If true, None can be used as a value for this field.
  • initial – Initial value to pass to factory if no value is given for the field.
Returns:

A field containing a CheckedPVector of the given type.

class PClass

A PClass is a python class with a fixed set of specified fields. PClasses are declared as python classes inheriting from PClass. It is defined the same way that PRecords are and behaves like a PRecord in all aspects except that it is not a PMap and hence not a collection but rather a plain Python object.

More documentation and examples of PClass usage is available at https://github.com/tobgu/pyrsistent

classmethod create(kwargs)

Factory method. Will create a new PClass of the current type and assign the values specified in kwargs.

evolver()

Returns an evolver for this object.

remove(name)

Remove attribute given by name from the current instance. Raises AttributeError if the attribute doesn’t exist.

serialize(format=None)

Serialize the current PClass using custom serializer functions for fields where such have been supplied.

set(*args, **kwargs)

Set a field in the instance. Returns a new instance with the updated value. The original instance remains unmodified. Accepts key-value pairs or single string representing the field name and a value.

>>> from pyrsistent import PClass, field
>>> class AClass(PClass):
...     x = field()
...
>>> a = AClass(x=1)
>>> a2 = a.set(x=2)
>>> a3 = a.set('x', 3)
>>> a
AClass(x=1)
>>> a2
AClass(x=2)
>>> a3
AClass(x=3)
transform(*transformations)

Apply transformations to the currency PClass. For more details on transformations see the documentation for PMap. Transformations on PClasses do not support key matching since the PClass is not a collection. Apart from that the transformations available for other persistent types work as expected.

immutable(members='', name='Immutable', verbose=False)

Produces a class that either can be used standalone or as a base class for persistent classes.

This is a thin wrapper around a named tuple.

Constructing a type and using it to instantiate objects:

>>> Point = immutable('x, y', name='Point')
>>> p = Point(1, 2)
>>> p2 = p.set(x=3)
>>> p
Point(x=1, y=2)
>>> p2
Point(x=3, y=2)

Inheriting from a constructed type. In this case no type name needs to be supplied:

>>> class PositivePoint(immutable('x, y')):
...     __slots__ = tuple()
...     def __new__(cls, x, y):
...         if x > 0 and y > 0:
...             return super(PositivePoint, cls).__new__(cls, x, y)
...         raise Exception('Coordinates must be positive!')
...
>>> p = PositivePoint(1, 2)
>>> p.set(x=3)
PositivePoint(x=3, y=2)
>>> p.set(y=-3)
Traceback (most recent call last):
Exception: Coordinates must be positive!

The persistent class also supports the notion of frozen members. The value of a frozen member cannot be updated. For example it could be used to implement an ID that should remain the same over time. A frozen member is denoted by a trailing underscore.

>>> Point = immutable('x, y, id_', name='Point')
>>> p = Point(1, 2, id_=17)
>>> p.set(x=3)
Point(x=3, y=2, id_=17)
>>> p.set(id_=18)
Traceback (most recent call last):
AttributeError: Cannot set frozen members id_
freeze(o)

Recursively convert simple Python containers into pyrsistent versions of those containers.

  • list is converted to pvector, recursively
  • dict is converted to pmap, recursively on values (but not keys)
  • set is converted to pset, but not recursively
  • tuple is converted to tuple, recursively.

Sets and dict keys are not recursively frozen because they do not contain mutable data by convention. The main exception to this rule is that dict keys and set elements are often instances of mutable objects that support hash-by-id, which this function can’t convert anyway.

>>> freeze(set([1, 2]))
pset([1, 2])
>>> freeze([1, {'a': 3}])
pvector([1, pmap({'a': 3})])
>>> freeze((1, []))
(1, pvector([]))
thaw(o)

Recursively convert pyrsistent containers into simple Python containers.

  • pvector is converted to list, recursively
  • pmap is converted to dict, recursively on values (but not keys)
  • pset is converted to set, but not recursively
  • tuple is converted to tuple, recursively.
>>> from pyrsistent import s, m, v
>>> thaw(s(1, 2))
set([1, 2])
>>> thaw(v(1, m(a=3)))
[1, {'a': 3}]
>>> thaw((1, v()))
(1, [])
mutant(fn)

Convenience decorator to isolate mutation to within the decorated function (with respect to the input arguments).

All arguments to the decorated function will be frozen so that they are guaranteed not to change. The return value is also frozen.

get_in(keys, coll, default=None, no_default=False)
NB: This is a straight copy of the get_in implementation found in
the toolz library (https://github.com/pytoolz/toolz/). It works with persistent data structures as well as the corresponding datastructures from the stdlib.

Returns coll[i0][i1]...[iX] where [i0, i1, ..., iX]==keys.

If coll[i0][i1]...[iX] cannot be found, returns default, unless no_default is specified, then it raises KeyError or IndexError.

get_in is a generalization of operator.getitem for nested data structures such as dictionaries and lists. >>> from pyrsistent import freeze >>> transaction = freeze({‘name’: ‘Alice’, ... ‘purchase’: {‘items’: [‘Apple’, ‘Orange’], ... ‘costs’: [0.50, 1.25]}, ... ‘credit card’: ‘5555-1234-1234-1234’}) >>> get_in([‘purchase’, ‘items’, 0], transaction) ‘Apple’ >>> get_in([‘name’], transaction) ‘Alice’ >>> get_in([‘purchase’, ‘total’], transaction) >>> get_in([‘purchase’, ‘items’, ‘apple’], transaction) >>> get_in([‘purchase’, ‘items’, 10], transaction) >>> get_in([‘purchase’, ‘total’], transaction, 0) 0 >>> get_in([‘y’], {}, no_default=True) Traceback (most recent call last):

...

KeyError: ‘y’

inc(x)

Add one to the current value

discard(evolver, key)

Discard the element and returns a structure without the discarded elements

rex(expr)

Regular expression matcher to use together with transform functions

ny(_)

Matcher that matches any value

Read the Docs v: latest
Versions
latest
stable
Downloads
pdf
htmlzip
epub
On Read the Docs
Project Home
Builds

Free document hosting provided by Read the Docs.