What we want to do

Replace some_key's value of '12345' in this dictionary:

data = {
    'top-level': {
        'second-level': {
            'some_key': '12345',
            'some_other_key': '54321',
            'another-level': {
                'nested_key': 'abc'
            }
        },
        'another-second-level': {
            'some_key': 'def'
        }
    }
}

with some_new_key's value of '67890' from this dictionary:

new_data = {
    'level-1': {
        'level-2': {
            'level-3': {
                'some_new_key': '67890',
                'some_other_new_key': '09876'
            }
        }
    }
}

Getting a nested value

We'll repeatedly attempt to get the next nested part of the dictionary. The final item in the path should get us the value of that item. If at any point it can't find the next item, this function will just return an empty string. 

import copy

def get_nested_value(dictionary, nested_path):
    """
    Return a value from a dictionary given a path-like nesting of keys.

    Will default to an empty string if value cannot be found.
    Args:
        dictionary (dict): a dictionary
        nested_path (str): nested/path/to/key
    Returns:
        ?: Value from dict
    """
    replacement_value_path = nested_path.split('/')
    replacement_value = copy.deepcopy(dictionary)

    for item in replacement_value_path:
        replacement_value = replacement_value.get(item, {})

    if replacement_value == {}:
        replacement_value = ''

    return replacement_value

 Replacing a nested value

This next function is a fun one that works because of a few things:

  1. Dictionaries in Python are mutable (meaning we can change them after creation)
  2. Most things in Python are objects (including dictionaries)
  3. Passing objects into functions in Python allow you to change the original object (if it's mutable, e.g. dictionaries)

Those three things allow the following to actually update the original dictionary:

def replace(data, path_to_key, replacement_value):
    """
    Will replace a nested value in a dict with the given value.
    Args:
        data (dict): a dictionary
        path_to_key (str): nested/path/to/key. The value of this key will be
            replaced
        replacement_value (str): Replacement value for the key from
            path_to_key
    """
    nested_path_to_replace = path_to_key.split('/')

    # follow dict to final key
    for item in nested_path_to_replace[:-1]:
        data = data.get(item, {})

    data.update(
        {str(nested_path_to_replace[-1]): replacement_value}
    )

Putting it all together!

data = {
    'top-level': {
        'second-level': {
            'some_key': '12345',
            'some_other_key': '54321',
            'another-level': {
                'nested_key': 'abc'
            }
        },
        'another-second-level': {
            'some_key': 'def'
        }
    }
}
new_data = {
    'level-1': {
        'level-2': {
            'level-3': {
                'some_new_key': '67890',
                'some_other_new_key': '09876'
            }
        }
    }
}

replacement_key = get_nested_value(
  new_data, 'level-1/level-2/level-3/some_new_key')

replace(
  data, 'top-level/second-level/some_key', replacement_key)

print(data)

After that, the data dictionary will have'67890' as the value for some_key. Note that we also did not modify any of the other items either, which is good. We just replaced what we wanted to.

{
    'top-level': {
        'second-level': {
            'some_key': '67890',
            'some_other_key': '54321',
            'another-level': {
                'nested_key': 'abc'
            }
        },
        'another-second-level': {
            'some_key': 'def'
        }
    }
}