views:

80

answers:

6

I'm trying to create a new variable that will consist of an existing dictionary so that I can change things in this new dictionary without it affecting the old one. When I try this below, which I think would be the obvious way to do this, it still seems to edit my original dictionary when I make edits to the new one.. I have been searching for info on this but can't seem to find anything, any info is appreciated

newdictionary = olddictionary
+5  A: 

You are just giving making newdictionary point to the same reference olddictionary points to. See this page (it's about lists, but it is also applicable to dicts).

alt text


Use .copy() instead (note: this creates a shallow copy):

newdictionary = olddictionary.copy()

To create a deep copy, you can use .deepcopy() from the copy module

newdictionary = copy.deepcopy(olddictionary)

Wikepedia :

Shallow vs Deep Copy

quantumSoup
ok thanks.. that clears it up for me
Rick
Note that this will create a shallow copy - items in the dictionary, such as lists or other dictionaries, will remain references to each other and your same problems will crop up again.
nearlymonolith
+1 awsome how'd you make that pic?
Claudiu
@Claudiu http://yuml.me
quantumSoup
+1 from me - that turned into a nice explanation. And I never knew of yuml before.
nearlymonolith
@Anthony Thanks. yuml is pretty cool, heh?
quantumSoup
+3  A: 

Assignment like that in Python just makes the newdictionary name refer to the same thing as olddictionary, as you've noticed. You can create a new dictionary with the dict() constructor:

newdictionary = dict(olddictionary)

Note that this makes a shallow copy. For deep copies, see the copy standard library module.

Greg Hewgill
That code simply is wrong.
delnan
@delnan: From the [`dict()`](http://docs.python.org/library/stdtypes.html#dict) documentation: "If the positional argument arg is a mapping object, return a dictionary mapping the same keys to the same values as does the mapping object."
Greg Hewgill
@delnan: No, it's correct.
Philipp
@delnan: Please share your wisdom in an understandable fashion: what code? what is wrong with it?
John Machin
Ouch, my apologies (and undownvote) then. Edit @John: I assumed dict() works the same for mappings as for all other iterables in that it simply iterates it (dicts yield only their keys by default), this wouldn't work. But as pointed out, it does handle mappings correctly.
delnan
+1  A: 
newdictionary = dict(olddictionary.items())

This creates a new copy (more specifically, it feeds the contents of olddict as (key,value) pairs to dict, which constructs a new dictionary from (key,value) pairs).

Edit: Oh yeah, copy - totally forgot it, that's the right way to do it.

a = b

just copies a reference, but not the object.

delnan
so its the same for any variable then? I guess I overlooked this aspect of python entirely up til this point as I'm very new to it still
Rick
@Rick: Yes, that's true for any Python variable. However, you won't notice for numbers and strings because they are not *mutable* values. Lists and dictionaries are mutable, though.
Greg Hewgill
Yes, it's the same for all types. Well, `a.b = c` is slightly different as it invokes a method of a (`__setattribute__` afaik) with c and b as parameters. But it still copies a reference by default. Edit gives @Greg Hewgill +1 for mentioning mutability.
delnan
thanks, great info to get me started on looking more into this topic
Rick
@delnan: Is this answer for Python 2.X or Python 3.X? If 2.X, don't you think that `iteritems` might be better? Why use either when there are better methods available?
John Machin
@John: I use Python 3, so I got used to iterators everywhere. My solution isn't the best anyway (I already edited and pointed to other people's answers).
delnan
A: 

You are merely creating another reference to the same dictionary.

You need to make a copy: use one of the following (after checking in the docs what each does):

new = dict(old)

new = old.copy()

import copy
new = copy.copy(old)

import copy
new = copy.deepcopy(old)
John Machin
+5  A: 

You're creating a reference, instead of a copy. In order to make a complete copy and leave the original untouched, you need copy.deepcopy(). So:

from copy import deepcopy
dictionary_new = deepcopy(dictionary_old)

Just using a = dict(b) or a = b.copy() will make a shallow copy and leave any lists in your dictionary as references to each other (so that although editing other items won't cause problems, editing the list in one dictionary will cause changes in the other dictionary, too).

nearlymonolith
thanks, this is the most simple / straightforward answer although I appreciate everyone helping me with this
Rick
A: 

I think you need a deep copy for what you are asking. See here.

It looks like dict.copy() does a shallow copy, which is what Rick does not want.

from copy import deepcopy
d = {}
d['names'] = ['Alfred', 'Bertrand']
c = d.copy()
dc = deepcopy(d)
Ethan Shepherd