Rob
Rob

Reputation: 169

Python Dictionary in Dictionary

>>> 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?

Upvotes: 0

Views: 372

Answers (6)

Andriy Ivaneyko
Andriy Ivaneyko

Reputation: 22071

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...

Upvotes: 3

Stefano
Stefano

Reputation: 3235

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"

Upvotes: 1

jlandercy
jlandercy

Reputation: 11097

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).

Upvotes: 2

Joël
Joël

Reputation: 2832

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)

Upvotes: 3

falsetru
falsetru

Reputation: 369454

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()
}

Upvotes: 2

Eran
Eran

Reputation: 2444

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.

Upvotes: 2

Related Questions