API Reference

lenses Module

A python module for manipulating deeply nested data structures without mutating them.

A simple overview for this module is available in the readme or at [http://github.com/ingolemo/python-lenses] . More detailed information for each object is available in the relevant docstrings. help(lenses.UnboundLens) is particularly useful.

The entry point to this library is the lens object:

>>> from lenses import lens
>>> lens
UnboundLens(TrivialIso())

You can also obtain a bound lens with the bind function.

>>> from lenses import bind
>>> bind([1, 2, 3])
BoundLens([1, 2, 3], TrivialIso())
class lenses.UnboundLens(optic)[source]

An unbound lens is a lens that has not been bound to any state.

Contains(item: A) BaseUiLens[S, S, bool, bool]

A lens that focuses a boolean that tells you whether the state contains some item.

>>> from lenses import lens
>>> lens.Contains(1)
UnboundLens(ContainsLens(1))
>>> lens.Contains(1).get()([2, 3])
False
>>> lens.Contains(1).get()([1, 2, 3])
True
>>> lens.Contains(1).set(False)([1, 2, 3])
[2, 3]
>>> lens.Contains(1).set(True)([2, 3])
[2, 3, 1]

The behaviour of this lens depends on the implementation of lenses.hooks.contains_add and lenses.hooks.contains_remove.

Decode(encoding: str = 'utf-8', errors: str = 'strict') BaseUiLens[S, T, bytes, str]

An isomorphism that decodes and encodes its focus on the fly. Lets you focus a byte string as a unicode string. The arguments have the same meanings as bytes.decode. Analogous to bytes.decode.

>>> from lenses import lens
>>> lens.Decode(encoding='utf8')
UnboundLens(DecodeIso('utf8', 'strict'))
>>> lens.Decode().get()(b'hello')
'hello'
>>> lens.Decode().set('world')(b'hello')
b'world'
Each() BaseUiLens[S, T, X, Y]

A traversal that iterates over its state, focusing everything it iterates over. It uses lenses.hooks.fromiter to reform the state afterwards so it should work with any iterable that function supports. Analogous to iter.

>>> from lenses import lens
>>> data = [1, 2, 3]
>>> lens.Each()
UnboundLens(EachTraversal())
>>> lens.Each().collect()(data)
[1, 2, 3]
>>> (lens.Each() + 1)(data)
[2, 3, 4]

For technical reasons, this lens iterates over dictionaries by their items and not just their keys.

>>> data = {'one': 1}
>>> lens.Each().collect()(data)
[('one', 1)]
>>> (lens.Each()[1] + 1)(data)
{'one': 2}
Error(exception: Exception, message: str | None = None) BaseUiLens[S, T, X, Y]

An optic that raises an exception whenever it tries to focus something. If message is None then the exception will be raised unmodified. If message is not None then when the lens is asked to focus something it will run message.format(state) and the exception will be called with the resulting formatted message as it’s only argument. Useful for debugging.

>>> from lenses import lens
>>> lens.Error(Exception())
UnboundLens(ErrorIso(Exception()))
>>> lens.Error(Exception, '{}')
UnboundLens(ErrorIso(<...Exception...>, '{}'))
>>> lens.Error(Exception).get()(True)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
Exception
>>> lens.Error(Exception('An error occurred')).set(False)(True)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
Exception: An error occurred
>>> lens.Error(ValueError, 'applied to {}').get()(True)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
ValueError: applied to True
F(getter: Callable[[A], X]) BaseUiLens[S, T, X, Y]

An optic that wraps a getter function. A getter function is one that takes a state and returns a value derived from that state. The function is called on the focus before it is returned.

>>> from lenses import lens
>>> lens.F(abs)
UnboundLens(Getter(<built-in function abs>))
>>> lens.F(abs).get()(-1)
1
>>> lens.Each().F(abs).collect()([-1, 2, -3])
[1, 2, 3]

This optic cannot be used to set or modify values.

Filter(predicate: Callable[[A], bool]) BaseUiLens[S, T, X, Y]

A prism that only focuses a value if the predicate returns True when called with that value as an argument. Best used when composed after a traversal. It only prevents the traversal from visiting foci, it does not filter out values the way that python’s regular filter function does.

>>> from lenses import lens
>>> lens.Filter(all)
UnboundLens(FilteringPrism(<built-in function all>))
>>> data = [[1, 2], [0], ['a'], ['', 'b']]
>>> lens.Each().Filter(all).collect()(data)
[[1, 2], ['a']]
>>> lens.Each().Filter(all).set(2)(data)
[2, [0], 2, ['', 'b']]

The filtering is done to foci before the lens’ manipulation is applied. This means that the resulting foci can still violate the predicate if the manipulating function doesn’t respect it:

>>> lens.Each().Filter(bool).set(None)(['', 2, ''])
['', None, '']
Fold(func: Callable[[A], Iterable[X]]) BaseUiLens[S, T, X, Y]

A fold that takes a function that returns an iterable and focuses all the values in that iterable.

>>> from lenses import lens
>>> def ends(state):
...     yield state[0]
...     yield state[-1]
>>> lens.Fold(ends).collect()([1, 2, 3])
[1, 3]
Fork(*lenses: BaseUiLens[A, B, X, Y]) BaseUiLens[S, T, X, Y]

A setter representing the parallel composition of several sub-lenses.

>>> from lenses import lens
>>> lens.Fork(lens[0], lens[2])
UnboundLens(ForkedSetter(GetitemLens(0), GetitemLens(2)))
>>> lens.Fork(lens[0][1], lens[2]).set(1)([[0, 0], 0, 0])
[[0, 1], 0, 1]
Get(key: Any, default: Y | None = None) BaseUiLens[S, T, X, Y]

A lens that focuses an item inside a container by calling its get method, allowing you to specify a default value for missing keys. Analogous to dict.get.

>>> from lenses import lens
>>> lens.Get('foo')
UnboundLens(GetitemOrElseLens('foo', default=None))
>>> lens.Get('baz').get()({'foo': 'bar'})
>>> lens.Get('baz', []).get()({'foo': 'bar'})
[]
>>> from collections import OrderedDict
>>> lens.Get('baz').set('qux')(OrderedDict({'foo': 'bar'}))
OrderedDict([('foo', 'bar'), ('baz', 'qux')])
GetAttr(name: str) BaseUiLens[S, T, X, Y]

A lens that focuses an attribute of an object. Analogous to getattr.

>>> from lenses import lens
>>> from collections import namedtuple
>>> Pair = namedtuple('Pair', 'left right')
>>> lens.GetAttr('left')
UnboundLens(GetattrLens('left'))
>>> lens.GetAttr('left').get()(Pair(1, 2))
1
>>> lens.GetAttr('right').set(3)(Pair(1, 2))
Pair(left=1, right=3)
GetItem(key: Any) BaseUiLens[S, T, X, Y]

A lens that focuses an item inside a container. Analogous to operator.itemgetter.

>>> from lenses import lens
>>> lens[0]
UnboundLens(GetitemLens(0))
>>> lens.GetItem(0)
UnboundLens(GetitemLens(0))
>>> lens[0].get()([1, 2, 3])
1
>>> lens['hello'].get()({'hello': 'world'})
'world'
>>> lens[0].set(4)([1, 2, 3])
[4, 2, 3]
>>> lens['hello'].set('universe')({'hello': 'world'})
{'hello': 'universe'}
GetZoomAttr(name: str) BaseUiLens[S, T, X, Y]

A traversal that focuses an attribute of an object, though if that attribute happens to be a lens it will zoom the lens. This is used internally to make lenses that are attributes of objects transparent. If you already know whether you are focusing a lens or a non-lens you should be explicit and use a ZoomAttrTraversal or a GetAttrLens respectively.

>>> from lenses import lens
>>> from collections import namedtuple
>>> Triple = namedtuple('Triple', 'left mid right')
>>> state = Triple(1, 2, lens.mid)
>>> lens.left
UnboundLens(GetZoomAttrTraversal('left'))
>>> lens.left.get()(state)
1
>>> lens.left.set(3)(state)
Triple(left=3, mid=2, right=UnboundLens(GetZoomAttrTraversal('mid')))
>>> lens.right.get()(state)
2
>>> lens.right.set(4)(state)
Triple(left=1, mid=4, right=UnboundLens(GetZoomAttrTraversal('mid')))
Instance(type_: Type) BaseUiLens[S, T, X, Y]

A prism that focuses a value only when that value is an instance of type_.

>>> from lenses import lens
>>> lens.Instance(int)
UnboundLens(InstancePrism(...))
>>> lens.Instance(int).collect()(1)
[1]
>>> lens.Instance(float).collect()(1)
[]
>>> lens.Instance(int).set(2)(1)
2
>>> lens.Instance(float).set(2)(1)
1
Iso(forwards: Callable[[A], X], backwards: Callable[[Y], B]) BaseUiLens[S, T, X, Y]

A lens based on an isomorphism. An isomorphism can be formed by two functions that mirror each other; they can convert forwards and backwards between a state and a focus without losing information. The difference between this and a regular Lens is that here the backwards functions don’t need to know anything about the original state in order to produce a new state.

These equalities should hold for the functions you supply (given a reasonable definition for __eq__):

backwards(forwards(state)) == state
forwards(backwards(focus)) == focus

These kinds of conversion functions are very common across the python ecosystem. For example, NumPy has np.array and np.ndarray.tolist for converting between python lists and its own arrays. Isomorphism makes it easy to store data in one form, but interact with it in a more convenient form.

>>> from lenses import lens
>>> lens.Iso(chr, ord)
UnboundLens(Isomorphism(<... chr>, <... ord>))
>>> lens.Iso(chr, ord).get()(65)
'A'
>>> lens.Iso(chr, ord).set('B')(65)
66

Due to their symmetry, isomorphisms can be flipped, thereby swapping thier forwards and backwards functions:

>>> flipped = lens.Iso(chr, ord).flip()
>>> flipped
UnboundLens(Isomorphism(<... ord>, <... chr>))
>>> flipped.get()('A')
65
Item(key: Any) BaseUiLens[S, T, X, Y]

A lens that focuses a single item (key-value pair) in a dictionary by its key. Set an item to None to remove it from the dictionary.

>>> from lenses import lens
>>> from collections import OrderedDict
>>> data = OrderedDict([(1, 10), (2, 20)])
>>> lens.Item(1)
UnboundLens(ItemLens(1))
>>> lens.Item(1).get()(data)
(1, 10)
>>> lens.Item(3).get()(data) is None
True
>>> lens.Item(1).set((1, 11))(data)
OrderedDict([(1, 11), (2, 20)])
>>> lens.Item(1).set(None)(data)
OrderedDict([(2, 20)])
ItemByValue(value: Any) BaseUiLens[S, T, X, Y]

A lens that focuses a single item (key-value pair) in a dictionary by its value. Set an item to None to remove it from the dictionary. This lens assumes that there will only be a single key with that particular value. If you violate that assumption then you’re on your own.

>>> from lenses import lens
>>> from collections import OrderedDict
>>> data = OrderedDict([(1, 10), (2, 20)])
>>> lens.ItemByValue(10)
UnboundLens(ItemByValueLens(10))
>>> lens.ItemByValue(10).get()(data)
(1, 10)
>>> lens.ItemByValue(30).get()(data) is None
True
>>> lens.ItemByValue(10).set((3, 10))(data)
OrderedDict([(2, 20), (3, 10)])
>>> lens.ItemByValue(10).set(None)(data)
OrderedDict([(2, 20)])
Items() BaseUiLens[S, T, X, Y]

A traversal focusing key-value tuples that are the items of a dictionary. Analogous to dict.items.

>>> from lenses import lens
>>> from collections import OrderedDict
>>> data = OrderedDict([(1, 10), (2, 20)])
>>> lens.Items()
UnboundLens(ItemsTraversal())
>>> lens.Items().collect()(data)
[(1, 10), (2, 20)]
>>> lens.Items()[1].modify(lambda n: n + 1)(data)
OrderedDict([(1, 11), (2, 21)])
Iter() BaseUiLens[S, T, X, Y]

A fold that can get values from any iterable object in python by iterating over it. Like any fold, you cannot set values.

>>> from lenses import lens
>>> lens.Iter()
UnboundLens(IterableFold())
>>> data = {2, 1, 3}
>>> lens.Iter().collect()(data) == list(data)
True
>>> def numbers():
...     yield 1
...     yield 2
...     yield 3
...
>>> lens.Iter().collect()(numbers())
[1, 2, 3]
>>> lens.Iter().collect()([])
[]

If you want to be able to set values as you iterate then look into the EachTraversal.

Json() BaseUiLens[S, T, X, Y]

An isomorphism that focuses a string containing json data as its parsed equivalent. Analogous to json.loads.

>>> from lenses import lens
>>> data = '[{"points": [4, 7]}]'
>>> lens.Json()
UnboundLens(JsonIso())
>>> lens.Json()[0]['points'][1].get()(data)
7
>>> lens.Json()[0]['points'][0].set(8)(data)
'[{"points": [8, 7]}]'
Just() BaseUiLens[S, T, X, Y]

A prism that focuses the value inside a lenses.maybe.Just object.

>>> from lenses import lens
>>> from lenses.maybe import Just, Nothing
>>> lens.Just()
UnboundLens(JustPrism())
>>> lens.Just().collect()(Just(1))
[1]
>>> lens.Just().collect()(Nothing())
[]
>>> lens.Just().set(2)(Just(1))
Just(2)
>>> lens.Just().set(2)(Nothing())
Nothing()
Keys() BaseUiLens[S, T, X, Y]

A traversal focusing the keys of a dictionary. Analogous to dict.keys.

>>> from lenses import lens
>>> from collections import OrderedDict
>>> data = OrderedDict([(1, 10), (2, 20)])
>>> lens.Keys()
UnboundLens(ItemsTraversal() & GetitemLens(0))
>>> lens.Keys().collect()(data)
[1, 2]
>>> lens.Keys().modify(lambda n: n + 1)(data)
OrderedDict([(2, 10), (3, 20)])
Lens(getter: Callable[[A], X], setter: Callable[[A, Y], B]) BaseUiLens[S, T, X, Y]

An optic that wraps a pair of getter and setter functions. A getter function is one that takes a state and returns a value derived from that state. A setter function takes an old state and a new value and uses them to construct a new state.

>>> from lenses import lens
>>> def getter(state):
...     'Get the average of a list'
...     return sum(state) // len(state)
...
>>> def setter(old_state, value):
...     'Set the average of a list by changing the final value'
...     target_sum = value * len(old_state)
...     prefix = old_state[:-1]
...     return prefix + [target_sum - sum(prefix)]
...
>>> average_lens = lens.Lens(getter, setter)
>>> average_lens
UnboundLens(Lens(<function getter...>, <function setter...>))
>>> average_lens.get()([1, 2, 4, 5])
3
>>> average_lens.set(4)([1, 2, 3])
[1, 2, 9]
>>> (average_lens - 1)([1, 2, 3])
[1, 2, 0]
Norm(setter: Callable[[A], X]) BaseUiLens[S, T, X, Y]

An isomorphism that applies a function as it sets a new focus without regard to the old state. It will get foci without transformation. This lens allows you to pre-process values before you set them, but still get values as they exist in the state. Useful for type conversions or normalising data.

For best results, your normalisation function should be idempotent. That is, applying the function twice should have no effect:

setter(setter(value)) == setter(value)

Equivalent to Isomorphism((lambda s: s), setter).

>>> from lenses import lens
>>> def real_only(num):
...     return num.real
...
>>> lens.Norm(real_only)
UnboundLens(NormalisingIso(<function real_only at ...>))
>>> lens[0].Norm(real_only).get()([1.0, 2.0, 3.0])
1.0
>>> lens[0].Norm(real_only).set(4+7j)([1.0, 2.0, 3.0])
[4.0, 2.0, 3.0]

Types with constructors that do conversion are often good targets for this lens:

>>> lens[0].Norm(int).set(4.0)([1, 2, 3])
[4, 2, 3]
>>> lens[1].Norm(int).set('5')([1, 2, 3])
[1, 5, 3]
Parts() BaseUiLens[S, T, X, Y]

Takes a Fold and turns it into a Getter by focusing a list of all the foci. If you use this method on a Traversal you will get back a Lens.

>>> from lenses import lens
>>> lens.Parts()
UnboundLens(PartsLens(TrivialIso()))
>>> lens.Each().Each().Parts()[0]
UnboundLens(PartsLens(EachTraversal() & EachTraversal()) & GetitemLens(0))
>>> state = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
>>> lens.Each().Each().Parts()[0].get()(state)
0
>>> lens.Each().Each().Parts()[0].set(9)(state)
[[9, 1, 2], [3, 4, 5], [6, 7, 8]]
Prism(unpack: Callable[[A], Just[X]], pack: Callable[[Y], B], ignore_none: bool = False, ignore_errors: tuple | None = None) BaseUiLens[S, T, X, Y]

A prism is an optic made from a pair of functions that pack and unpack a state where the unpacking process can potentially fail.

pack is a function that takes a focus and returns that focus wrapped up in a new state. unpack is a function that takes a state and unpacks it to get a focus. The unpack function may choose to fail to unpack a focus, either by returning None or raising an exception (or both).

All prisms are also traversals that have exactly zero or one foci.

You must pass one or both of the ignore_none=True or ignore_errors=True keyword arguments. If you pass the former then the prism will fail to focus anything when your unpacking function returns None. If you pass the latter then it will fail to focus when your unpacking function raises an error.

>>> from lenses import lens
>>> lens.Prism(int, str)
Traceback (most recent call last):
  File "<stdin>", line 1 in ?
ValueError: Must specify what to ignore
>>> lens.Prism(int, str, ignore_errors=True)
UnboundLens(Prism(..., ...))
>>> lens.Prism(int, str, ignore_errors=True).collect()('42')
[42]
>>> lens.Prism(int, str, ignore_errors=True).collect()('fourty two')
[]

If you set ignore_errors to True then it will catch any and all exceptions. A better alternative is to set it to a tuple of exception types to ignore (such as you would pass to isinstance).

>>> errors = (ValueError,)
>>> lens.Prism(int, str, ignore_errors=errors)
UnboundLens(Prism(..., ...))
>>> lens.Prism(int, str, ignore_errors=errors).collect()('42')
[42]
>>> lens.Prism(int, str, ignore_errors=errors).collect()('fourty two')
[]
>>> lens.Prism(int, str, ignore_errors=errors).collect()([1, 2, 3])
Traceback (most recent call last):
  File "<stdin>", line 1 in ?
TypeError: int() argument must be ...
Recur(cls)

A traversal that recurses through an object focusing everything it can find of a particular type. This traversal will probe arbitrarily deep into the contents of the state looking for sub-objects. It uses some naughty tricks to do this including looking at an object’s __dict__ attribute.

It is somewhat analogous to haskell’s uniplate optic.

>>> from lenses import lens
>>> lens.Recur(int)
UnboundLens(RecurTraversal(<... 'int'>))
>>> data = [[1, 2, 100.0], [3, 'hello', [{}, 4], 5]]
>>> lens.Recur(int).collect()(data)
[1, 2, 3, 4, 5]
>>> (lens.Recur(int) + 1)(data)
[[2, 3, 100.0], [4, 'hello', [{}, 5], 6]]

It also works on custom classes:

>>> class Container(object):
...     def __init__(self, contents):
...         self.contents = contents
...     def __repr__(self):
...         return 'Container({!r})'.format(self.contents)
>>> data = [Container(1), 2, Container(Container(3)), [4, 5]]
>>> (lens.Recur(int) + 1)(data)
[Container(2), 3, Container(Container(4)), [5, 6]]
>>> lens.Recur(Container).collect()(data)
[Container(1), Container(Container(3))]

Be careful with this; it can focus things you might not expect.

Regex(pattern: str | Pattern, flags: int = 0) BaseUiLens[S, T, str, str]

A traversal that uses a regex to focus parts of a string. flags has the same meaning as it does in the re module.

>>> from lenses import lens
>>> words = lens.Regex(r'\w+')
>>> words
UnboundLens(RegexTraversal(re.compile('\\w+'), flags=0))
>>> state = "First thou pullest the Holy Pin"
>>> words.collect()(state)
['First', 'thou', 'pullest', 'the', 'Holy', 'Pin']
>>> state & words + '!'
'First! thou! pullest! the! Holy! Pin!'
Traversal(folder: Callable[[A], Iterable[X]], builder: Callable[[A, Iterable[Y]], B]) BaseUiLens[S, T, X, Y]

An optic that wraps folder and builder functions.

The folder function is a function that takes a single argument - the state - and returns an iterable containing all the foci that exist in that state. Generators are a good option for writing folder functions.

A builder function takes the old state and an list of values and constructs a new state with the old state’s values swapped out. The number of values passed to builder for any given state should always be the same as the number of values that the folder function would have returned for that same state.

>>> from lenses import lens
>>> def ends_folder(state):
...     'Yields the first and last elements of a list'
...     yield state[0]
...     yield state[-1]
>>> def ends_builder(state, values):
...     'Sets the first and last elements of a list'
...     result = list(state)
...     result[0] = values[0]
...     result[-1] = values[1]
...     return result
>>> both_ends = lens.Traversal(ends_folder, ends_builder)
>>> both_ends
UnboundLens(Traversal(...ends_folder..., ...ends_builder...))
>>> both_ends.collect()([1, 2, 3, 4])
[1, 4]
>>> both_ends.set(5)([1, 2, 3, 4])
[5, 2, 3, 5]
Tuple(*lenses: BaseUiLens[A, B, X, Y]) BaseUiLens[S, T, X, Y]

An optic that combines the focuses of other optics into a single tuple. The suboptics must not be Folds or Traversals.

>>> from lenses import lens
>>> lens.Tuple()
UnboundLens(TupleOptic())
>>> tl = lens.Tuple(lens[0], lens[2])
>>> tl
UnboundLens(TupleOptic(GetitemLens(0), GetitemLens(2)))
>>> tl.get()([1, 2, 3, 4])
(1, 3)
>>> tl.set((5, 6))([1, 2, 3, 4])
[5, 2, 6, 4]

This lens is particularly useful when immediately followed by an EachLens, allowing you to traverse data even when it comes from disparate locations within the state.

>>> state = ([1, 2, 3], 4, [5, 6])
>>> tl.Each().Each().collect()(state)
[1, 2, 3, 5, 6]
>>> (tl.Each().Each() + 10)(state)
([11, 12, 13], 4, [15, 16])
Values() BaseUiLens[S, T, X, Y]

A traversal focusing the values of a dictionary. Analogous to dict.values.

>>> from lenses import lens
>>> from collections import OrderedDict
>>> data = OrderedDict([(1, 10), (2, 20)])
>>> lens.Values()
UnboundLens(ItemsTraversal() & GetitemLens(1))
>>> lens.Values().collect()(data)
[10, 20]
>>> lens.Values().modify(lambda n: n + 1)(data)
OrderedDict([(1, 11), (2, 21)])
Zoom() BaseUiLens[S, T, X, Y]

Follows its state as if it were a BoundLens object.

>>> from lenses import lens, bind
>>> data = [bind([1, 2])[1], 4]
>>> lens.Zoom()
UnboundLens(ZoomTraversal())
>>> lens[0].Zoom().get()(data)
2
>>> lens[0].Zoom().set(3)(data)
[[1, 3], 4]
ZoomAttr(name: str) BaseUiLens[S, T, X, Y]

A lens that looks up an attribute on its target and follows it as if were a BoundLens object. Ignores the state, if any, of the lens that is being looked up.

>>> from lenses import lens
>>> class ClassWithLens(object):
...     def __init__(self, items):
...         self._private_items = items
...     def __repr__(self):
...         return 'ClassWithLens({!r})'.format(self._private_items)
...     first = lens._private_items[0]
...
>>> data = (ClassWithLens([1, 2, 3]), 4)
>>> lens.ZoomAttr('first')
UnboundLens(ZoomAttrTraversal('first'))
>>> lens[0].ZoomAttr('first').get()(data)
1
>>> lens[0].ZoomAttr('first').set(5)(data)
(ClassWithLens([5, 2, 3]), 4)
add_lens(other)

Refine the current focus of this lens by composing it with another lens object. The other lens must be unbound.

>>> from lenses import lens
>>> first = lens[0]
>>> second = lens[1]
>>> second_first = second & first
>>> get_second_then_first = second_first.get()
>>> get_second_then_first([[0, 1], [2, 3]])
2
bitwise_and(other: Any) T

Uses the bitwise and operator on the focus. A convenience method since lenses use __and__ for doing composition.

>>> from lenses import lens
>>> lens.Each().bitwise_and(5)([1, 2, 3, 4])
[1, 0, 1, 4]
call(method_name: str, *args: Any, **kwargs: Any) T

Call a method on the focus. The method must return a new value for the focus.

>>> from lenses import lens
>>> lens[2].call('upper')(['alpha', 'beta', 'gamma'])
['alpha', 'beta', 'GAMMA']

As a shortcut, you can include the name of the method you want to call immediately after call_:

>>> lens[2].call_upper()(['alpha', 'beta', 'gamma'])
['alpha', 'beta', 'GAMMA']
call_mut(method_name: str, *args: Any, **kwargs: Any) T

Call a method on the focus that will mutate it in place. Works by making a deep copy of the focus before calling the mutating method on it. The return value of that method is ignored. You can pass a keyword argument shallow=True to only make a shallow copy.

>>> from lenses import lens
>>> lens[0].call_mut('sort')([[3, 1, 2], [5, 4]])
[[1, 2, 3], [5, 4]]

As a shortcut, you can include the name of the method you want to call immediately after call_mut_:

>>> lens[0].call_mut_sort()([[3, 1, 2], [5, 4]])
[[1, 2, 3], [5, 4]]
collect() StateFunction[S, List[B]][source]

Get multiple values focused by the lens. Returns them as a list.

>>> from lenses import lens
>>> collect_each_first = lens.Each()[0].collect()
>>> collect_each_first([(1, 2), (3, 4), (5, 6)])
[1, 3, 5]
construct(focus: A) S[source]

Construct a state given a focus.

flip() UnboundLens[A, B, S, T][source]

Flips the direction of the lens. The lens must be unbound and all the underlying operations must be isomorphisms.

>>> from lenses import lens
>>> json_encoder = lens.Decode().Json().flip()
>>> json_encode = json_encoder.get()
>>> json_encode(['hello', 'world'])
b'["hello", "world"]'
get() StateFunction[S, B][source]

Get the first value focused by the lens.

>>> from lenses import lens
>>> getter = lens.get()
>>> getter([1, 2, 3])
[1, 2, 3]
>>> zero_item_getter = lens[0].get()
>>> zero_item_getter([1, 2, 3])
1
get_monoid() StateFunction[S, B][source]

Get the values focused by the lens, merging them together by treating them as a monoid. See lenses.typeclass.mappend.

>>> from lenses import lens
>>> get_each_monoidally = lens.Each().get_monoid()
>>> get_each_monoidally([[], [1], [2, 3]])
[1, 2, 3]
kind() str[source]

Returns the “kind” of the lens.

modify(func: Callable[[A], B]) StateFunction[S, T][source]

Apply a function to the focus.

>>> from lenses import lens
>>> convert_item_one_to_string = lens[1].modify(str)
>>> convert_item_one_to_string([1, 2, 3])
[1, '2', 3]
>>> add_ten_to_item_one = lens[1].modify(lambda n: n + 10)
>>> add_ten_to_item_one([1, 2, 3])
[1, 12, 3]
set(newvalue: B) StateFunction[S, T][source]

Set the focus to newvalue.

>>> from lenses import lens
>>> set_item_one_to_four = lens[1].set(4)
>>> set_item_one_to_four([1, 2, 3])
[1, 4, 3]
set_many(new_values: Iterable[B]) StateFunction[S, T][source]

Set many foci to values taken by iterating over new_values.

>>> from lenses import lens
>>> lens.Each().set_many(range(4, 7))([0, 1, 2])
[4, 5, 6]

lenses.hooks Module

This module contains functions that you can hook into to allow various lenses to operate on your own custom data structures.

You can hook into them by defining a method that starts with _lens_ followed by the name of the hook function. So, for example: the hook for lenses.hooks.contains_add is a method called _lens_contains_add. This is the preferred way of hooking into this library because it does not require you to have the lenses library as a hard dependency.

These functions are all decorated with singledispatch, allowing you to customise the behaviour of types that you did not write. Be warned that single dispatch functions are registered globally across your program and that your function also needs to be able to deal with subclasses of any types you register (or else register separate functions for each subclass).

All of these hooks operate in the following order:

  • Use an implementation registered with singledispatch.register for the relevant type, if one exists.

  • Use the relevant _lens_* method on the first object that was passed in, if it exists.

  • Use a default implementation that is likely to work for most python objects, if one exists.

  • Raise NotImplementedError.

lenses.hooks.contains_add(self: Any, item: Any) Any[source]
lenses.hooks.contains_add(self: List[A], item: A) List[A]
lenses.hooks.contains_add(self: Tuple[A, ...], item: A) Tuple[A, ...]
lenses.hooks.contains_add(self: Dict[A, Any], item: A) Dict[A, Any]
lenses.hooks.contains_add(self: Set[A], item: A) Set[A]

Takes a collection and an item and returns a new collection of the same type that contains the item. The notion of “contains” is defined by the object itself; The following must be True:

item in contains_add(obj, item)

This function is used by some lenses (particularly ContainsLens) to add new items to containers when necessary.

The corresponding method call for this hook is obj._lens_contains_add(item).

There is no default implementation.

lenses.hooks.contains_remove(self: Any, item: Any) Any[source]
lenses.hooks.contains_remove(self: List[A], item: A) List[A]
lenses.hooks.contains_remove(self: Tuple[A, ...], item: A) Tuple[A, ...]
lenses.hooks.contains_remove(self: Dict[A, B], item: A) Dict[A, B]
lenses.hooks.contains_remove(self: Set[A], item: A) Set[A]

Takes a collection and an item and returns a new collection of the same type with that item removed. The notion of “contains” is defined by the object itself; the following must be True:

item not in contains_remove(obj, item)

This function is used by some lenses (particularly ContainsLens) to remove items from containers when necessary.

The corresponding method call for this hook is obj._lens_contains_remove(item).

There is no default implementation.

lenses.hooks.from_iter(self: Any, iterable: Any) Any[source]
lenses.hooks.from_iter(self: bytes, iterable: Iterable[int]) bytes
lenses.hooks.from_iter(self: str, iterable: Iterable[str]) str
lenses.hooks.from_iter(self: Dict, iterable: Iterable[Tuple[A, B]]) Dict[A, B]
lenses.hooks.from_iter(self: List, iterable: Iterable[A]) List[A]
lenses.hooks.from_iter(self: Set, iterable: Iterable[A]) Set[A]
lenses.hooks.from_iter(self: FrozenSet, iterable: Iterable[A]) FrozenSet[A]
lenses.hooks.from_iter(self: tuple, iterable)
lenses.hooks.from_iter(self: Just, iter: Iterator[A]) Just[A]

Takes an object and an iterable and produces a new object that is a copy of the original with data from iterable reincorporated. It is intended as the inverse of the to_iter function. Any state in self that is not modelled by the iterable should remain unchanged.

The following equality should hold for your definition:

from_iter(self, to_iter(self)) == self

This function is used by EachLens to synthesise states from iterables, allowing it to focus every element of an iterable state.

The corresponding method call for this hook is obj._lens_from_iter(iterable).

There is no default implementation.

lenses.hooks.setattr(self: Any, name: Any, value: Any) Any[source]
lenses.hooks.setattr(self: NamedTuple, name: str, value: A) NamedTuple

Takes an object, a string, and a value and produces a new object that is a copy of the original but with the attribute called name set to value.

The following equality should hold for your definition:

setattr(obj, 'attr', obj.attr) == obj

This function is used by many lenses (particularly GetattrLens) to set attributes on states even when those states do not ordinarily support setattr. This function is designed to have a similar signature as python’s built-in setattr except that it returns a new object that has the attribute set rather than mutating the object in place.

It’s what enables the lens.some_attribute functionality.

The corresponding method call for this hook is obj._lens_setattr(name, value).

The default implementation makes a copy of the object using copy.copy and then mutates the new object by calling python’s built in setattr on it.

lenses.hooks.setitem(self: Any, key: Any, value: Any) Any[source]
lenses.hooks.setitem(self: bytes, key: int, value: int) bytes
lenses.hooks.setitem(self: str, key: int, value: str) str
lenses.hooks.setitem(self: Tuple[A, ...], key: int, value: A) Tuple[A, ...]

Takes an object, a key, and a value and produces a new object that is a copy of the original but with value as the new value of key.

The following equality should hold for your definition:

setitem(obj, key, obj[key]) == obj

This function is used by many lenses (particularly GetitemLens) to set items on states even when those states do not ordinarily support setitem. This function is designed to have a similar signature as python’s built-in setitem except that it returns a new object that has the item set rather than mutating the object in place.

It’s what enables the lens[some_key] functionality.

The corresponding method call for this hook is obj._lens_setitem(key, value).

The default implementation makes a copy of the object using copy.copy and then mutates the new object by setting the item on it in the conventional way.

lenses.hooks.to_iter(self: Any) Any[source]
lenses.hooks.to_iter(self: Dict[A, B]) Iterator[Tuple[A, B]]

Takes an object and produces an iterable. It is intended as the inverse of the from_iter function.

The reason this hook exists is to customise how dictionaries are iterated. In order to properly reconstruct a dictionary from an iterable you need access to both the keys and the values. So this function iterates over dictionaries by thier items instead.

The corresponding method call for this hook is obj._lens_to_iter().

The default implementation is to call python’s built in iter function.