Everyone who's done Python for a while soon learns that dicts are mutable. I.e. that they can change.

One way of "forking" a dictionary into two different ones is to create a new dictionary object with dict(). E.g:


>>> first = {'key': 'value'}
>>> second = dict(first)
>>> second['key'] = 'other'
>>> first
{'key': 'value'}
>>> second
{'key': 'other'}

See, you can change the value of a key without affecting the dictionary it came from.

But, if one of the values is also mutable, beware!


>>> first = {'key': ['value']}
>>> second = dict(first)
>>> second['key'].append('second value')
>>> first
{'key': ['value', 'second value']}
>>> second
{'key': ['value', 'second value']}

This is where you need to use the built in copy.deepcopy.


>>> import copy
>>> first = {'key': ['value']}
>>> second = copy.deepcopy(first)
>>> second['key'].append('second value')
>>> first
{'key': ['value']}
>>> second
{'key': ['value', 'second value']}

Yay! Hope it helps someone avoid some possibly confusing bugs some day.

UPDATE

As ëRiC reminded me, there are actually three ways to make a "shallow copy" of a dictionary:

1) some_copy = dict(some_dict)

2) some_copy = some_dict.copy()

3) some_copy = copy.copy(some_dict) # after importing 'copy'

Comments

Post your own comment
aRkadeFR

wow... thanks for the post :)

ëRiC

Dicts have a copy method right away!

    d = {'asdf': ['value']}
    dd = d.copy()
    dd['asdf'] = ['other']
    d
    # Result: {'asdf': ['value']} #
    dd
    # Result: {'asdf': ['other']} #

(can it really be!? I contributed something?!! :D)

Peter Hansen

Note that using obj.copy() should probably be preferred to dict(obj) since the former approach allows someone to override the copy operation in subclasses whereas the latter does not.

Although by default obj.copy() returns a dict, if someone has chosen to return an instance of the type(obj) then only that approach will have the intended result. (As with any such advice, this applies to the general case but not, by definition, if you have a good reason to do it differently.)

James

Awesome post thank you

David

Thank YOU so much!

Ilya Rusin

copy.deepcopy is way slower than dict comprehension -
https://stackoverflow.com/questions/20772885/is-python-deepcopy-more-efficient-than-custom-code-or-less-efficient-predictabl

"The reasons why deepcopy is so much slower than the dict comprehension + list copy are:

 - deepcopy is multi-purpose function - it works for mostly any kind of object
 - deepcopy is implemented in python whilst dict comprehension and list slicing is done at lower level

And most imporantly:

 - deepcopy makes copies of the elements inside containers recursively, whilst your dict comprehension does not."

Peter Bengtsson

But if it's the same object (after a dict comprehension spin), then it risky that it's mutable and gets changed by something that you didn't expect. That's functionally different so it can't really be compared performance-wise.

Jan

thanks a lot, so many years later, still saved me!

Kai Franke

Me too! Changing dictionaries in a loop and couldn't find what is messing me up the resulting dictionary. THANKS!!!

Your email will never ever be published.

Related posts