Nested attribute getter/setter that works with dictionaries and objects interchangeably.
Project description
nattrs
Nested attributes utility functions for python. Allows getting/setting of object attributes and dict members interchangeably. Useful to populate nested dicts for storing outputs of a loop.
The functions should work with most dict types (i.e. Mapping
/ MutableMapping
) and classes.
Tip: Attribute names can be found using regular expressions.
Installation
Install from PyPI:
pip install nattrs
Install from GitHub:
python -m pip install git+https://github.com/ludvigolsen/nattrs
Main functions
Class/Function | Description |
---|---|
nested_getattr |
Get object attributes/dict members recursively, given by dot-separated names. |
nested_setattr |
Set object attribute/dict member by recursive lookup, given by dot-separated names. |
nested_mutattr |
Apply function (mutate) to object attribute/dict member by recursive lookup, given by dot-separated names. |
nested_updattr |
Update dict / class.dict of attributes recursively, given by dot-separated names. |
nested_hasattr |
Check whether recursive object attributes/dict members exist. |
nested_delattr |
Delete object attributes/dict members recursively, given by dot-separated names. |
populate_product |
Create and populate nested dicts with specified layers and the same leaf value. |
Examples
Create class B
with a dict c
with the member d
:
class B:
def __init__(self):
self.c = {
"d": 1
}
Add to a dict a
:
a = {"b": B()}
nested_getattr
Get the value of d
:
nested_getattr(a, "b.c.d")
>> 1
Get default value when not finding an attribute:
nested_getattr(a, "b.o.p", default="not found")
>> "not found"
nested_setattr
Set the value of d
:
nested_setattr(a, "b.c.d", 2)
Check new value of d
:
nested_getattr(a, "b.c.d")
>> 2
nested_mutattr
Mutate d
with an anonymous function (lambda):
nested_mutattr(a, "b.c.d", lambda x: x * 5)
Check new value of d
:
nested_getattr(a, "b.c.d")
>> 10
Note: If your function performs the assignment in-place, remember to enable the is_inplace_fn
argument.
nested_updattr
Update d
with a dictionary:
nested_updattr(a, "b.c.d", {"d": 3})
Check new value of d
:
nested_getattr(a, "b.c.d")
>> 3
Note: Also work on class.__dict__
dicts.
nested_hasattr
Check presence of the member 'd':
nested_hasattr(a, "b.c.d")
>> True
Fail to find member 'o':
nested_hasattr(a, "b.o.p")
>> False
nested_delattr
Delete the member 'd':
nested_delattr(a, "b.c.d")
nested_hasattr(a, "b.c.d")
>> False
Ignore that it fails to find member 'o':
nested_delattr(a, "b.o.p", allow_missing=True)
populate_product
In this example, we wish to pre-populate nested dicts with empty lists to allow appending within a for
loop. First, we go through the manual approach of doing this. Second, we show how easy it is to do with populate_product()
.
Say we have 3 variables that can each hold 2 values. We want to compute something for each combination of these values. Let's first define these variables and their options:
animal = ["cat", "dog"]
food = ["strawberry", "cucumber"]
temperature = ["cold", "warm"]
Let's generate the product of these options:
import itertools
combinations = list(itertools.product(*[animal, food, temperature]))
combinations
>> [('cat', 'strawberry', 'cold'),
>> ('cat', 'strawberry', 'warm'),
>> ('cat', 'cucumber', 'cold'),
>> ('cat', 'cucumber', 'warm'),
>> ('dog', 'strawberry', 'cold'),
>> ('dog', 'strawberry', 'warm'),
>> ('dog', 'cucumber', 'cold'),
>> ('dog', 'cucumber', 'warm')]
Now we can create a nested dict structure with a list in the leaf element:
# Initialize empty dict
nested_dict = {}
for leaf in combinations:
# Join each string with dot-separation:
attr = ".".join(list(leaf))
# Assign empty list to the leafs
# `make_missing` creates dicts for each
# missing attribute/dict member
nattrs.nested_setattr(
obj=nested_dict,
attr=attr,
value=[],
make_missing=True
)
nested_dict
>> {'cat': {'strawberry': {'cold': [], 'warm': []},
>> 'cucumber': {'cold': [], 'warm': []}},
>> 'dog': {'strawberry': {'cold': [], 'warm': []},
>> 'cucumber': {'cold': [], 'warm': []}}}
This dict population is actually provided by populate_product()
. Instead of an empty list, let's set the value to an "edibility" score that could be changed by a later function:
layers = [animal, food, temperature]
populate_product(
layers=layers,
val=False
)
>> {'cat': {'strawberry': {'cold': False, 'warm': False},
>> 'cucumber': {'cold': False, 'warm': False}},
>> 'dog': {'strawberry': {'cold': False, 'warm': False},
>> 'cucumber': {'cold': False, 'warm': False}}}
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file nattrs-0.2.2.tar.gz
.
File metadata
- Download URL: nattrs-0.2.2.tar.gz
- Upload date:
- Size: 14.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.4.0 CPython/3.9.6 Darwin/21.6.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 533686a410dd9facbb4c83b74b0894a947ca9cd279becc436f0ae0080ca0f3f0 |
|
MD5 | a0590b967ccd827f996d30b61e23f741 |
|
BLAKE2b-256 | 4049d18ef6c24e2a0723ae2b116ebb74726e358256450f952eccfe7b433fe658 |
File details
Details for the file nattrs-0.2.2-py3-none-any.whl
.
File metadata
- Download URL: nattrs-0.2.2-py3-none-any.whl
- Upload date:
- Size: 20.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.4.0 CPython/3.9.6 Darwin/21.6.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 3fe1294c4a2e1c7e5772fc37908e64940072a93c1d3c722c6f6b95dbeddf23c3 |
|
MD5 | 06105524b75eb08a0643bf6f0e666ab7 |
|
BLAKE2b-256 | 4cd6052ff5356a1f1c54f88709c0697253727dcc6cfedc74cf0090d660375f50 |