tailor
tailor

Reputation: 15

python references, nested dicts and 'del' produce unexpected behaviour

This is more a question out of interest. I observed the following behaviour and would like to know why / how this happens (tried in python 2.7.3 & python 3.4.1)

ph = {1:0, 2:0}
d1 = {'a':ph, 'b':ph}
d2 = {'a':{1:0,2:0},{'b':{1:0,2:0}}
>>> d1
{'a':{1:0,2:0},{'b':{1:0,2:0}}

so d1 and d2 are the same. However when using del or replacing values this happens

>>> del d1['a'][1]
>>> d1
{'a':{2:0}, 'b':{2:0}}
>>> del d2['a'][1]
>>> d2
{'a':{2:0},{'b':{1:0,2:0}}

The behaviour for d2 is as expected, but the nested dictionaries in d1 (ph) seem to work differently. Is it because all variables in python are really references? Is there a work around if I can't specify the placeholder dictionary for every instance?

Thank you!

Upvotes: 0

Views: 66

Answers (2)

Jimbo
Jimbo

Reputation: 4515

Try using pythontutor. If you put your code into it you will see this:

enter image description here

You can see that as you suspected the dictionaries in d1 are references to the same object, ph.

This means that when you del d1['a'][1] it really deletes a key in ph so you get this:

enter image description here

To work around this you need to initialise d1 with copies of the ph dictionary, as discussed in other answers here...

Upvotes: 3

Chris
Chris

Reputation: 6392

Both keys in d1 point to the same reference, so when you delete from d1 it affects ph whether you reach it by d1['a'] or d1['b'] - you're getting to the same place.

d2 on the other hand instantiates two separate objects, so you're only affecting one of those in your example.

Your workaround would be .deepcopy() for your second reference in d1.

d1 = {'a':ph, 'b':ph.deepcopy()}

(You don't really need deepcopy in this example - copy() would be sufficient - but if ph were any more complex you would - see the above linked docs.)

Upvotes: 1

Related Questions