Subhankar Halder
Subhankar Halder

Reputation: 47

Please explain this behavior of Python dictionary

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

Answers (5)

FMc
FMc

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

Dynamis Luchs
Dynamis Luchs

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

YosSaL
YosSaL

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

Itai Ben Amram
Itai Ben Amram

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

Dr. V
Dr. V

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

Related Questions