{"id":9886,"library":"lenses","title":"Python Lenses","description":"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.","status":"active","version":"1.2.0","language":"en","source_language":"en","source_url":"https://github.com/ingolemo/python-lenses","tags":["functional programming","data manipulation","immutability","lenses"],"install":[{"cmd":"pip install lenses","lang":"bash","label":"Install stable version"}],"dependencies":[],"imports":[{"symbol":"lens","correct":"from lenses import lens"}],"quickstart":{"code":"from lenses import lens\n\ndata = {\n    'user': {\n        'id': 123,\n        'name': 'Alice',\n        'settings': {\n            'theme': 'dark',\n            'notifications': True\n        }\n    },\n    'products': [{'id': 'A', 'price': 100}, {'id': 'B', 'price': 200}]\n}\n\n# Get a value\nuser_name = lens(data).user.name.get()\nprint(f\"User name: {user_name}\")\n\n# Set a new value (returns a new data structure)\nupdated_data = lens(data).user.settings.theme.set('light')\nprint(f\"Original theme: {data['user']['settings']['theme']}\")\nprint(f\"New theme: {updated_data['user']['settings']['theme']}\")\n\n# Modify a value (returns a new data structure)\nincreased_price_data = lens(data).products[0].price.modify(lambda p: p * 1.1)\nprint(f\"Original product A price: {data['products'][0]['price']}\")\nprint(f\"Increased product A price: {increased_price_data['products'][0]['price']}\")","lang":"python","description":"Demonstrates basic `get()`, `set()`, and `modify()` operations for navigating and transforming nested immutable data structures."},"warnings":[{"fix":"Always assign the result of a `set()` or `modify()` operation to a new variable or overwrite the original if desired, e.g., `data = lens(data).path.set(new_value)`.","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Use `lens(data)['key']` for dictionaries to ensure robust key access. Attribute access `lens(data).key` is syntactic sugar that might rely on custom `__getattr__` implementations or `dict` subclasses.","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"fix":"To handle missing keys gracefully, use methods like `lens(data).path.get_set(default_value)` which provides a fallback value if the path is not found, or `lens(data).path.get_0(default_value)` for an optional value.","message":"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.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-17T00:00:00.000Z","next_check":"2026-07-16T00:00:00.000Z","problems":[{"fix":"Use 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`.","cause":"Attempting to access a dictionary key using attribute notation (`.foo`) when the underlying `dict` object does not support attribute access for its keys.","error":"AttributeError: 'dict' object has no attribute 'foo'"},{"fix":"Before `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.","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.","error":"KeyError: 'some_key' or IndexError: list index out of range"},{"fix":"Ensure 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`.","cause":"Trying to use a lens object or one of its methods without calling the terminal operation (e.g., `get`, `set`, `modify`) with parentheses.","error":"TypeError: 'lens' object is not callable"}]}