Reputation: 47
Consider the following code:
# Case 1
a = dict()
b = dict()
a = {'name': 'Bob'}
b['0'] = a
print("Initial a: ", a)
print("Initial b:", b)
print("")
a['name'] = 'Lucy'
print("Intermediate a: ", a)
print("Intermediate b: ", b)
print("")
We get our output:
Initial a: {'name': 'Bob'}
Initial b: {'0': {'name': 'Bob'}}
Intermediate a: {'name': 'Lucy'}
Intermediate b: {'0': {'name': 'Lucy'}}
So changing the value of 'a', changes 'b' as well. I believe this is due to the mutable character of the dictionary.
Now, consider this snippet:
# Case 2
a = dict()
b = dict()
a = {'name': 'Bob'}
b['0'] = a
print("Initial a: ", a)
print("Initial b:", b)
print("")
a = dict()
print("Intermediate a: ", a)
print("Intermediate b", b)
print("")
The output is:
Initial a: {'name': 'Bob'}
Initial b: {'0': {'name': 'Bob'}}
Intermediate a: {}
Intermediate b: {'0': {'name': 'Bob'}}
Why doesn't intermediate b value become an empty dictionary for key 0 for # case 2?
Upvotes: 1
Views: 87
Reputation: 42411
Here is an illustration from a Python REPL session.
In [1]: a = {1: 2} # A couple of dicts similar to your example.
In [2]: b = {0: a}
In [3]: id(a) # Every object in a Python program has a unique ID.
Out[3]: 4442001056
In [4]: id(b[0]) # Note that both `a` and `b[0]` refer to the same object.
Out[4]: 4442001056
# Variable names are like labels. You can attach multiple
# labels to the same underlying object. We already have
# two ways to refer to object 4442001056: using `a` or `b[0]`.
In [5]: x = a # Let's add another way.
In [6]: id(x) # Again it's the same underlying object.
Out[6]: 4442001056
In [7]: a[77] = 77 # Let's modify object 4442001056 in various ways.
In [8]: b[0][88] = 88
In [9]: x[99] = 99
# The changes are reflected everywhere.
In [10]: a
Out[10]: {1: 2, 77: 77, 88: 88, 99: 99}
In [11]: b
Out[11]: {0: {1: 2, 77: 77, 88: 88, 99: 99}}
In [12]: x
Out[12]: {1: 2, 77: 77, 88: 88, 99: 99}
# Now let's attach the label `a` to a different object --
# in this case object 4427016088.
In [13]: a = {'hello': 'world'}
In [14]: id(a)
Out[14]: 4427016088
# Nothing happens to object 4442001056.
In [15]: b
Out[15]: {0: {1: 2, 77: 77, 88: 88, 99: 99}}
In [16]: x
Out[16]: {1: 2, 77: 77, 88: 88, 99: 99}
Also see Ned Batchelder's piece on Python names and values.
Upvotes: 1
Reputation: 9
In the first case "a" and b ['0'] point to the same memory address so when you make a change to "a" it also affects b ["0"] In case two, when you assign a new dictionary to the variable "a", you do not overwrite the memory address that houses the old dictionary (also pointed by b [0]). Variable a now points to a new memory address that contains the new dictionary, the old one if not pointed to by any variable would be removed from memory but being pointed to by b [0] remains intact
Upvotes: 1
Reputation: 1027
I guess dr. v has answered your question but an extra information tip is when you want to easily copy an object in python you can use copy built-in module:
from copy import deepcopy
a = {'hamed': 12, 'dr.v': 20}
b = deepcopy(a)
a['new'] = 'is this in b too?'
print(f'a is ({a}) b is ({b})
and the output is:
a is ({'hamed': 12, 'dr.v': 20, 'new': 'is this in b too?'}) b is ({'hamed': 12, 'dr.v': 20})
Upvotes: 1
Reputation: 178
I recommend you check out the code using http://www.pythontutor.com/
you'll see that by creating a
new dict in case #2 python keeps the current pointer of b
at the same memory location but allocates a
to a new location in memory,
since b
is still pointing at the old memory location, when changing a
, it does not affect b
.
Upvotes: 0
Reputation: 1914
When you assign a new dictionary to a
, it is a new independent object, and a
loses the reference to its old value. This reference is still kept as member of b
.
For me it is more surprising how Bob
turns into Lucy
in your second snipplet. :-D
Upvotes: 2