Change value in dictionary

I would like to know how I can change a value in a dictionary using list of keys and 1 value

my_dict = {
    'bob': {
        'name': {'first': 'FirstName', 'last': 'LastName'},
        'job': 'Developer'
    }
}

string1 = 'bob.name.first=Bob'
string1 = string.split('=')
string2 = string1[0].split('.')
string2.append(string[1])

Here I end up with a list of 4 items, the first 3 are keys and the last is the value.

How can I use this given list to change the value in my_dict considering that the given list keys number can be changed for example if I want to change bob.job=QA

5 answers

  • answered 2017-10-11 10:03 AK47

    If you want to update Bob's job you can access it using my_dict['bob']['job']

    my_dict = {
        'bob': {
            'name': {'first': 'FirstName', 'last': 'LastName'},
            'job': 'Developer'
        }
    }
    
    my_dict['bob']['job'] = 'QA'
    
    print(my_dict)
    >> {'bob': {'name': {'last': 'LastName', 'first': 'FirstName'}, 'job': 'QA'}}
    

    or by splitting your string:

    my_dict = {
        'bob': {
            'name': {'first': 'FirstName', 'last': 'LastName'},
            'job': 'Developer'
        }
    }
    
    bobjob_key_value = 'bob.job=QA'
    key, value = bobjob_key_value.split('=')
    key = key.split('.')
    my_dict[key[0]][key[1]] = value
    
    print(my_dict)
    
    >> {'bob': {'job': 'QA', 'name': {'last': 'LastName', 'first': 'FirstName'}}}
    

  • answered 2017-10-11 10:03 makkhi

    You can write:

    string1 = 'bob.name.first=Bob'
    string1,string2 = string1.split('=')
    string1 = string1.split('.')
    my_dict[string1[0]][string1[1]][string1[2]] = string2
    

  • answered 2017-10-11 10:03 Vinny

    You want a dict with keys that can be accessed as attributes. You can achieve that by subclassing dict class, and add support for your need. I think this is more pythonic solution as it is much more intuative:

    class MyDict(dict):
        def __getattr__(self, attr):
            return self[attr] if attr in self.keys() else None
    
        def __setattr__(self, attr, value):
            self[attr] = value
    
    my_dict = MyDict({
        'bob': MyDict(
            {'name':
             MyDict({'first': 'FirstName', 'last': 'LastName'}),
             'job':'Developer'})})
    
    >>> my_dict.bob
    {'job': 'Developer', 'name': {'last': 'LastName', 'first': 'FirstName'}}
    >>> my_dict.bob.job
    'Developer'
    >>> my_dict.bob.name
    {'last': 'LastName', 'first': 'FirstName'}
    

    It does require some overhead, as you will need to build your dicts based on MyDict. Regular dicts won't work if added to this dict.

    This supports setting a new value as well:

    >>> my_dict.bob.job = 'QA'
    >>> my_dict.bob.job
    'QA'
    

  • answered 2017-10-11 10:03 Fabio Caccamo

    I suppose the following function is what you are looking for, it works with any number of keys and creates intermediates dictionaries if not exist yet.

    d = {
        'bob': {
            'name': {
                'first': 'FirstName', 
                'last': 'LastName'
            },
            'job': 'Developer'
        }
    }
    
    def update_dict_by_expr(d, expr):
        keys_value = expr.split('=')
        keys = keys_value[0].split('.')
        value = keys_value[1]
        item = d
        while len(keys) > 1:
            key = keys.pop(0)
            if key not in item:
                item[key] = {}
            item = item[key]
        key = keys[0]
        item[key] = value
    
    print(d)
    update_dict_by_expr(d, 'bob.name.first=Bob Junior')
    update_dict_by_expr(d, 'bob.name.birth.date=01/01/2017')
    update_dict_by_expr(d, 'bob.name.birth.place=NYC')
    print(d)
    

  • answered 2017-10-11 10:03 Idan Shamami

    import yaml
    
    
    def get_dictionary_replace_value(file, new_value, strip_qoutes=True):
    
        with open(file, 'r') as rf:
            yaml_doc = yaml.load(rf)
            rf.close()
    
        key, value = new_value.split('=')
        keys = key.split('.')
        inner_dict = yaml_doc
    
        for i in keys[:-1]:
            inner_dict = inner_dict[i]
        inner_dict[keys[-1]] = value
    
        with open(file, 'w') as wf:
            if strip_qoutes:
                wf.write(yaml.dump(yaml_doc, 
                default_flow_style=False).replace("'", "").replace('"', ""))
            else:
                wf.write(yaml.dump(yaml_doc, default_flow_style=False))
        wf.close()