0
>>> docsite = {'text1':1, 'text2':1}

>>> doc = {    
    'field1': docsite,
    'field2': docsite
}

>>> doc['field2']['text1'] += 2

after this when i print doc variable, i get

>>> doc
{'field2': {'text2': 1, 'text1': 3}, 'field1': {'text2': 1, 'text1': 3}}

I change value in field2 only. Somehow, values in field1 is also getting updated.

Question:

  1. Why?

  2. How to resolve it?

Andriy Ivaneyko
  • 20,639
  • 6
  • 60
  • 82
Rob
  • 169
  • 2
  • 4
  • 15

6 Answers6

3

Dict's are mutable objects in python. When you assign dict to other variable it's assigned by reference, what leads to problem you have described.

So in your case both values of keys in doc dict (field1,field2) point to same variable (docsite). That's way you have such behaviour.

To fix that use dict copy method before assigning it to doc keys.

docsite = {'text1':1, "text2":1}

doc = {    
"field1": docsite.copy(),
"field2": docsite.copy()
}

There are two types of copies in python, deepcopy and shallow copy ( see that SO answer to understand difference between them).

The example above is just shallow copy of docsite. However you can make deepcopy by using code below:

import copy


docsite = {'text1':1, "text2":1}

doc = {    
"field1": copy.deepcopy(docsite),
"field2": copy.deepcopy(docsite)
}

See Immutable vs Mutable types that's good SO question to discover that topic for python...

Community
  • 1
  • 1
Andriy Ivaneyko
  • 20,639
  • 6
  • 60
  • 82
3

Your docsite variable is a reference to a dictionnary, therefore, storing it at different locations (e.g. associated to different keys in another dictionary) will make them share the same dictionary in memory.

To resolve this, you may want to do a copy of your dictionary:

doc = {'field1': docsite, 'field2': docsite.copy()}

Note that, if in docsite you have references to other objects (list, other dict, etc) then you may have to use a deepcopy:

import copy
d2 = copy.deepcopy(docsite)
Joël
  • 2,723
  • 18
  • 36
2
import copy
doc = {    
"field1":docsite,
"field2":copy.deepcopy(docsite)
}

Both keys in doc map to the same object, when you change the value of one key you are changing the docsite object, same object the other key also map to.

Eran
  • 2,324
  • 3
  • 22
  • 27
2

Because the values in the doc dictionary refers the same dictionary object.

To solve, pass copies of the dictionaries, so that values refers different dictionary objects:

doc = {    
    "field1": dict(docsite),  # or docsite.copy()
    "field2": dict(docsite),  # or docsite.copy()
}
falsetru
  • 357,413
  • 63
  • 732
  • 636
2

Python does not work with copy of object, when assigning your fields to docsite, both satellite values are pointing towards the same object. You can check using id() method: id(doc['field2']) == doc['field1']. Use deepcopy if you need different copy of your initial object.

import copy
doc['field2'] = copy.deepcopy(docsite)

Update: Of course, this will require to import the copy module in order to use it (as underlined by Andriy Ivaneyko).

jlandercy
  • 7,183
  • 1
  • 39
  • 57
  • that code would fails because `copy` module not imported. – Andriy Ivaneyko Jan 27 '16 at 15:18
  • @Andriy Ivaneyko, You are right. This answer does not intend to provide a full working code, it just underlines that mutable object are passed by reference and that why deepcopy exists. Is this a sufficient reason to downvote? Fixed anyway – jlandercy Jan 27 '16 at 15:24
  • you would confuse user without pointing to copy module, because it looks like `deepcopy` is are built-in method of python without such pointing... – Andriy Ivaneyko Jan 27 '16 at 15:42
1

In your second dictionary you save the pointer to docsite. So, when you change it, it will change for all.

To solve it you have to copy.

doc = {    
    "field1":docsite.copy(),
    "field2":docsite.copy(),
}

I'm not sure about copy function, if it doesn't work just try to google "python clone dictionary"

Andriy Ivaneyko
  • 20,639
  • 6
  • 60
  • 82
Stefano
  • 3,127
  • 2
  • 27
  • 33