Reputation: 35404
Let's say we want to create/maintain a dict with below key structure
{
"a": {"bb": {"01": "some value 01",
"02": "some value 02",
} },
}
We use dpath .new() as below to do this
import dpath
d=dict() ; print(d) # d={}
dpath.new(d,'a/bb/00/c', '00val') ; print(d) # d={'a': {'bb': [{'c': '00val'}]}}
# d # NOTE this will set :bb as a list, and set at bb[00] ie idx=0 of list bb
# d # what we want instead is d={'a': {'bb': {'00': {'c': '00val'} }}}
# d # what we want is NOT d={'a': {'bb': [ {'c': '00val'} ]}}
So when using 00
in the path, dpath translate it into list index at 0
instead of dict key 00
The question is how to set key as 00
? Currently I have to dodge it by setting prefix s
ie s00
s01
s02
Upvotes: 1
Views: 66
Reputation: 35404
If you can drop dpath, let's write ourself version mget_dict(d, key_path)
def mget_dict(d:dict, key_path, val_whnotfound=None):
"""
ref https://g.co/gemini/share/06e7f2ced5d8
recursively retrieves a value from a nested dictionary.
"""
if not isinstance(key_path, list): return None
if not key_path: return d
key = key_path[0]
if not d.get(key): return val_whnotfound
else: return mget_dict(d[key], key_path[1:], val_whnotfound) # recursively go next level
Upvotes: 0
Reputation: 5871
I traced into the source, and noticed that it calls a Creator, documented in the function as:
creator allows you to pass in a creator method that is
responsible for creating missing keys at arbitrary levels of
the path (see the help for dpath.path.set)
I copied _default_creator from dpath.segments, and just eliminated the code that treats int values as a list index. Here's the quick and dirty version:
import dpath
from dpath.segments import extend
from typing import Sequence, MutableSequence
def my_creator(current, segments, i, hints):
segment = segments[i]
length = len(segments)
if isinstance(current, Sequence):
segment = int(segment)
if isinstance(current, MutableSequence):
extend(current, segment)
# Infer the type from the hints provided.
if i < len(hints):
current[segment] = hints[i][1]()
else:
# deleted the array stuff here
current[segment] = {}
d = dict()
dpath.new(d, r'a/bb/00/c', '00val', creator=my_creator)
print(d)
output
{'a': {'bb': {'00': {'c': '00val'}}}}
Upvotes: 1
Reputation: 21
The simple way using dpath
is as show below where new
is used to create or update the path in dict and path representation will be take care using root
and zero padded keys are considered as string instead of integer.
import dpath.util
# Initialize an empty dictionary
data = {}
# Adding keys '00', '01', '02' as strings
keys = ["00", "01", "02"]
for key in keys:
dpath.util.new(data, f"root/{key}", f"value_for_{key}")
# Display the resulting dictionary
print(data)
Upvotes: 1