Convert list to a sequence of dictionary keys

Question:

I have 2 dictionaries

old_dict = {'key1': {'password1': 'password', 'sensitive_data': {'MY_PASSWORD': 'old_passwrd'}},
            'key2': 'next_password', 'useless_key': 'useless_pass'}

new_dict = {'key1': {'password1': 'password', 'sensitive_data': {'MY_PASSWORD': 'default_password'}},
            'key2': 'next_password'}

Next code parses the keys in the new dictionary and takes values ​​from the old one and inserts them into the new one

def find_old(val_dict, value_list):
    for i in value_list:
        val_dict = val_dict[i]
    return val_dict


def change_value(val_dict, value_list, value):
    if len(value_list) == 1:
        val_dict[value_list[0]] = value
    elif len(value_list) == 2:
        val_dict[value_list[0]][value_list[1]] = value
    elif len(value_list) == 3:
        val_dict[value_list[0]][value_list[1]][value_list[2]] = value


def parser(parse_dict, value_list=None, level=0):
    if value_list is None:
        value_list = []
    for i in parse_dict:
        value_list = value_list[:level]
        value_list.append(i)
        next_val = parse_dict[i]
        if type(next_val) is dict:
            parser(next_val, value_list, level=level + 1)
        else:
            old_value = (find_old(old_dict, value_list))
            change_value(new_dict, value_list, old_value)


parser(parse_dict=new_dict)
print(new_dict) # {'key1': {'password1': 'password', 'sensitive_data': {'MY_PASSWORD': 'old_passwrd'}}, 'key2': 'next_password'}

the code works, but the change_value function can only work with 3 levels of dictionary keys. how to convert this function into a loop?

Asked By: Alex Die

||

Answers:

There is already an operator that implements this future (Python 3.9). Its name is merge and the operator is |, syntax: dict_1 | dict_2 (official doc).
Python will overwrite the left dictionary with the value of the keys from the right dictionary if there is an overlap, otherwise it will merge.

In your example, with these dictionaries:

old_dict = {
    'key1': {
        'password1': 'password',
        'sensitive_data': {
            'MY_PASSWORD': 'old_passwrd'
        }
    },
    'key2': 'next_password',
    'useless_key': 'useless_pass'
}

new_dict = {
    'key1': {
        'password1': 'password',
        'sensitive_data': {
            'MY_PASSWORD': 'default_password'
        }
    },
    'key2': 'next_password'
}

The code is:

new_dict = new_dict | old_dict

If you want to remove useless_key as well, you can use a recursion function:

def _rmv_item(obj: dict, key_to_rmv: str):
    # remove useless key
    if key_to_rmv in obj: obj.pop(key_to_rmv)
    # search other dictionaries
    for k, v in obj.items():
        if isinstance(v, dict):
            _rmv_item(v, key_to_rmv)

def _rmv_items(obj: dict, keys_to_rmv: list[str]):
    # remove useless key
    for key in keys_to_rmv:
        if key in obj:
            obj.pop(key)
    # search other dictionaries
    for k, v in obj.items():
        if isinstance(v, dict):
            _rmv_items(v, keys_to_rmv)
Answered By: AndreVale69

I figered out and it works

def change_value(val_dict, value_list, value):
    key_seq = val_dict
    for index, i in enumerate(value_list):
        if index != len(value_list)-1:
            key_seq = key_seq[i]
        else:
            key_seq[i] = value
Answered By: Alex Die
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.