Reputation: 3001
I'm using Python 3.5.1
So what I am trying to do is pass in a dict a dot separated string representing the path to a key and a default value. I want to check for the keys existence and if it's not there , provide the default value. The problem with this is that the key I want to access could be nested in other dicts and I will not know until run time. So what I want to do is something like this:
def replace_key(the_dict, dict_key, default_value):
if dict_key not in the_dict:
the_dict[dict_key] = default_value
return the_dict
some_dict = {'top_property': {'first_nested': {'second_nested': 'the value'}}}
key_to_replace = 'top_property.first_nested.second_nested'
default_value = 'replaced'
#this would return as {'top_property': {'first_nested': {'second_nested': 'replaced'}}}
replace_key(some_dict, key_to_replace, default_value)
What I'm looking for is a way to do this without having to do a split on '.' in the string and iterating over the possible keys as this could get messy. I would rather not have to use a third party library. I feel like there is clean built in Pythonic way to do this but I just can't find it. I've dug through the docs but to no avail. If anyone has any suggestion as to how I could do this it would be very much appreciated. Thanks!
Upvotes: 1
Views: 1174
Reputation: 309
the easyest way that I've found to do this, namely get value using a "key path" by "dotted string" is using replace and eval:
for key in pfields:
if key.find('.') > 0:
key = key.replace(".", "']['")
try:
data = str(eval(f"row['{key}']"))
except KeyError:
data = ''
And this is an example of the keys:
lfields = ['cpeid','metadata.LinkAccount','metadata.DeviceType','metadata.SoftwareVersion','mode_props.vfo.CR07.VIKPresence','mode_props.vfo.CR13.VIBHardVersion']
With this raw solution You don't need install other library
Upvotes: -2
Reputation: 450
You could use recursivity:
def replace_key(the_dict, dict_keys, default_value):
if dict_keys[0] in the_dict:
if len(dict_keys)==1:
the_dict[dict_keys[0]]=default_value
else:
replace_key(the_dict[dict_keys[0]], dict_keys[1:],default_value)
else:
raise Exception("wrong key")
some_dict = {'top_property': {'first_nested': {'second_nested': 'the value'}}}
key_to_replace = 'top_property.first_nested.second_nested'
default_value = 'replaced'
#this would return as {'top_property': {'first_nested': {'second_nested': 'replaced'}}}
replace_key(some_dict, key_to_replace.split("."), default_value)
But it still uses the split(). But maybe you consider it to be less messy?
Upvotes: 3