bgbg bgbg - 18 days ago 6
Python Question

How to copy a dict and modify it in one line of code

Very often I need to create dicts that differ one from another by an item or two. Here is what I usually do:

setup1 = {'param1': val1,
'param2': val2,
'param3': val3,
'param4': val4,
'paramN': valN}

setup2 = copy.deepcopy(dict(setup1))
setup2.update({'param1': val10,
'param2': val20})


The fact that there is a point in the program at which
setup2
is an identical copy of
setup1
makes me nervous, as I'm afraid that at some point of the program life the two lines might get separated, which is a slippery slope towards too many bugs.

Ideally I would like to be able to complete this action in a single line of code (something like this):

setup2 = dict(setup1).merge({'param1': val10,
'param2': val20})


Of course, I can use semicolon to squeeze two commands into one physical line, but this looks pretty ugly to me. Are there other options?

Answer

Solution

Build a function for that.

Your intention would be clearer when you use it in the code, and you can handle complicated decisions (e.g., deep versus shallow copy) in a single place.

def copy_dict(source_dict, diffs):
    """Returns a copy of source_dict, updated with the new key-value
       pairs in diffs."""
    result=dict(source_dict) # Shallow copy, see addendum below
    result.update(diffs)
    return result

And now the copy is atomic, assuming no threads involved:

setup2=copy_dict(setup1, {'param1': val10, 'param2': val20})

Addendum - deep copy

For primitives (integers and strings), there is no need for deep copy:

>>> d1={1:'s', 2:'g', 3:'c'}
>>> d2=dict(d1)
>>> d1[1]='a'
>>> d1
{1: 'a', 2: 'g', 3: 'c'}
>>> d2
{1: 's', 2: 'g', 3: 'c'}

If you need a deep copy, use the copy module:

result=copy.deepcopy(source_dict) # Deep copy

instead of:

result=dict(setup1)               # Shallow copy

Make sure all the objects in your dictionary supports deep copy (any object that can be pickled should do).

Comments