Python Lenses
Lenses is a Python library inspired by functional programming concepts, providing a fluent API for immutable data manipulation. It allows for safe and concise modification, retrieval, and transformation of nested data structures (like dictionaries and lists) without mutating the original object. The current version is 1.2.0, with a moderate release cadence.
Common errors
-
AttributeError: 'dict' object has no attribute 'foo'
cause Attempting to access a dictionary key using attribute notation (`.foo`) when the underlying `dict` object does not support attribute access for its keys.fixUse item access `lens(data)['foo']` instead of `lens(data).foo`. While `lens` itself enables the `.foo` syntax, the error often originates when the underlying data is being accessed through a plain `dict`. -
KeyError: 'some_key' or IndexError: list index out of range
cause The path specified by the lens (e.g., `some_key` or `list_index`) does not exist in the data structure during a `get()` operation or when modifying.fixBefore `get()`, `set()`, or `modify()`, ensure the path exists, or use methods like `lens(data).path.get_set(default_value)` to provide a fallback value if the path is not found. -
TypeError: 'lens' object is not callable
cause Trying to use a lens object or one of its methods without calling the terminal operation (e.g., `get`, `set`, `modify`) with parentheses.fixEnsure all terminal operations are called with parentheses, even if they take no arguments, e.g., `lens(data).foo.get()` instead of `lens(data).foo.get`.
Warnings
- gotcha Lenses operations are immutable. They *always* return a new modified copy of the data structure, leaving the original unchanged. Expecting in-place modification will lead to silent failures where the original data remains unaltered.
- gotcha When navigating nested data, be mindful of using attribute access (`.key`) vs. item access (`['key']` or `[index]`). Attribute access assumes dictionary keys can be accessed like attributes, which is convenient but can lead to `AttributeError` if the underlying dictionary type doesn't support it directly.
- gotcha Lenses throw `KeyError` or `IndexError` by default if a path component does not exist during a `get()` operation. This can lead to unexpected crashes if data structures vary.
Install
-
pip install lenses
Imports
- lens
from lenses import lens
Quickstart
from lenses import lens
data = {
'user': {
'id': 123,
'name': 'Alice',
'settings': {
'theme': 'dark',
'notifications': True
}
},
'products': [{'id': 'A', 'price': 100}, {'id': 'B', 'price': 200}]
}
# Get a value
user_name = lens(data).user.name.get()
print(f"User name: {user_name}")
# Set a new value (returns a new data structure)
updated_data = lens(data).user.settings.theme.set('light')
print(f"Original theme: {data['user']['settings']['theme']}")
print(f"New theme: {updated_data['user']['settings']['theme']}")
# Modify a value (returns a new data structure)
increased_price_data = lens(data).products[0].price.modify(lambda p: p * 1.1)
print(f"Original product A price: {data['products'][0]['price']}")
print(f"Increased product A price: {increased_price_data['products'][0]['price']}")