Skip to content

Instantly share code, notes, and snippets.

@eladn
Created October 18, 2023 11:20
Show Gist options
  • Select an option

  • Save eladn/13f25bbee32a73448d6700974ad25a6f to your computer and use it in GitHub Desktop.

Select an option

Save eladn/13f25bbee32a73448d6700974ad25a6f to your computer and use it in GitHub Desktop.
Python functions for accessing a nested dictionary by a dot-separated key for reading and setting values and creating missing dictionaries in nested levels.
__author__ = "Elad Nachmias"
__email__ = "[email protected]"
__date__ = "2023-10-18"
from typing import Dict, Any
def access_nested_dict_by_dot_key(
dct: Dict, key: str, create_missing: bool = False, replace_nones: bool = False) -> Any:
"""
Access a nested dict in the given input dict by accessing a sequence of keys (given as a single string in which the
sub-keys are separated by dots) one after the other. If one of the keys in the sequence doesn't exist (and/or is
None) it can be created as a dict. For example, for key='k1.k2.k3' it would return dct['k1']['k2']['k3'].
:param dct: the root level of the input dictionary to be accessed
:param key: sequence of keys given as a single string where the keys are separated by dots
:param create_missing: if True, for each non-existing sub-key an empty dict would be appended in its parent under
that sub-key
:param replace_nones: if True, for each sub-key that is mapped to None at its parent dict, the None value would be
replaced with a new empty dictionary.
"""
sub_keys = key.split('.')
dict_type = dct.__class__
# Iterate over all keys except the last one and make sure they're all nested dictionaries.
for sub_key_idx, sub_key in enumerate(sub_keys):
if sub_key not in dct:
if not create_missing:
return None
sub_dict = dct[sub_key] = dict_type()
else:
sub_dict = dct[sub_key]
if sub_dict is None:
if not replace_nones:
return None
sub_dict = dct[sub_key] = dict_type()
if not isinstance(sub_dict, (dict, dict_type)):
raise ValueError(
f"Key prefix `{'.'.join(sub_keys[:sub_key_idx + 1])}` already exists "
f"with non dict type `{type(sub_dict)}`.")
dct = sub_dict
return dct
def get_or_set_nested_dict_value_by_dot_key(
dct: Dict, key: str, default_value: Any,
replace_none_value: bool = True, replace_none_parents: bool = True) -> Any:
"""
Access a nested dict in the given input dict by accessing a sequence of keys (given as a single string in which the
sub-keys are separated by dots) one after the other. If one of the keys in the sequence doesn't exist (and/or is
None) it can be created as a dict. For example, for key='k1.k2.k3' it would return dct['k1']['k2']['k3'].
Additionally, if the last sub-key doesn't exist in its corresponding parent dictionary, it would be added to this
dict with the given default value.
:param dct: the root level of the input dictionary to be accessed
:param key: sequence of keys given as a single string where the keys are separated by dots
:param default_value: a value to be assigned to the record of the last sub-key if it doesn't already set
:param replace_none_value: if True, override the entry of the last sub-key (in its corresponding parent dictionary)
with the given default value
:param replace_none_parents: if True, for each sub-key (except the last one) that is mapped to None at its
corresponding parent dict, it would be replaced with a new empty dictionary.
"""
sub_keys = key.split('.')
last_sub_key = sub_keys[-1]
direct_parent_dict_key = '.'.join(sub_keys[:-1])
direct_parent_dict = access_nested_dict_by_dot_key(
dct=dct, key=direct_parent_dict_key, create_missing=True, replace_nones=replace_none_parents)
if last_sub_key not in direct_parent_dict or (replace_none_value and direct_parent_dict[last_sub_key] is None):
direct_parent_dict[last_sub_key] = default_value
return direct_parent_dict[last_sub_key]
def set_nested_dict_value_by_dot_key(
dct: Dict, key: str, value: Any,
create_missing_parents: bool = False, replace_none_parents: bool = False):
"""
Assign a value under for a given nested key in the given input nested dict, where the given key is a sequence of
sub-keys (given as a single string in which the sub-keys are separated by dots). For example, for key='k1.k2.k3'
it would assign dct['k1']['k2']['k3'] := value.
:param dct: the root level of the input dictionary to be accessed and/or updated
:param key: sequence of keys given as a single string where the keys are separated by dots
:param value: a value to be assigned to the record of the last sub-key
:param create_missing_parents: if True, for each non-existing sub-key (except the last one) an empty dict would be
appended in its parent under that sub-key
:param replace_none_parents: if True, for each sub-key (except the last one) that is mapped to None at its parent
dict, the None value would be replaced with a new empty dictionary
"""
sub_keys = key.split('.')
last_sub_key = sub_keys[-1]
direct_parent_dict_key = '.'.join(sub_keys[:-1])
direct_parent_dict = access_nested_dict_by_dot_key(
dct=dct,
key=direct_parent_dict_key,
create_missing=create_missing_parents,
replace_nones=replace_none_parents)
direct_parent_dict[last_sub_key] = value
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment