Different behavior in initiating multiple dictionaries and multiple constants

I can initiate multiple const and change only one of them

c2 = c3 = c4 = 5
c2 += 4
c2
>>9
c3
>>5

but for dicitionaries, the values change with the other dictionaries. Why?

d4 = d5 = d6 = {}
d4['a'] = pd.DataFrame({'time': pd.date_range(start = '2012-01-01', end = '2012-12-31', freq = 'Q-Dec'), 'value': [1,2,5,6]})
d4
>>{'a':         time  value
 0 2012-03-31      1
 1 2012-06-30      2
 2 2012-09-30      5
 3 2012-12-31      6}
d5
>>{'a':         time  value
 0 2012-03-31      1
 1 2012-06-30      2
 2 2012-09-30      5
 3 2012-12-31      6}
d6
>>{'a':         time  value
 0 2012-03-31      1
 1 2012-06-30      2
 2 2012-09-30      5
 3 2012-12-31      6}

int are immutable. When you do c2 += 4 the object 5 that c2 refers to, is not changed. Instead a new one, 9, is assigned to c2, which c3 and c4 are still referring to the original, unchanged, object 5.

On the other hand, in the case of the dictionary, all your variables are referring to the same dictionary. The assignment to d4['a'] is modifying that one object.

1 Like

But that’s not what you are doing! Your code c2 = c3 = c4 = 5 initiates three names for the same value, not three different values that happen to equal 5.

They aren’t constants because you then go on to add 4 to c2. If it were a constant, you could not change it.

In Python, all values, even ints, are objects. (If you are familiar with Java, all values in Python are boxed.) Some objects are mutable and can change their internal value.

After you have set the names c2, c3 and c4 to the object 5, you cannot change its value because ints are immutable. All you can do is replace the object with a different object:

c2 = c3 = c4 = 5  # Three names referring to the same object, like "Me, Myself and I".
# c2 += 4 is a shortcut for c2 = c2 + 4
c2 = c2 + 4  # this changes the name c2 to refer to a new object, namely 5+4 = 9
print(c2, c3, c4)

But the other two names still refer to the same 5 object, because we haven’t assigned a new value to them.

Now let’s do the same with dicts. Assignment works the same way:

d2 = d3 = d4 = {'spam': 6, 'eggs': 7}  # Three names referring to the same object.
d2 = {'spam': 99, 'eggs': 111, 'aardvark': 42}  # Change the name d2 to refer to a new object. 
print(c2, c3, c4)

Again, we assign a new value to d2, and leave d3 and d4 untouched.

But now, instead of doing an assignment, let’s mutate the dict in place, without reassigning.

e2 = e3 = e4 = {'spam': 6, 'eggs': 7}  # Three names referring to the same object.
e2['aardvark'] = 8  # This modifies the dict object in place.
print(e2, e3, e4)

Since e2, e3 and e4 are just three names for the same object, you will see the same dict printed out three times.

One object can have many names. If you mutate or modify that object, it doesn’t matter which name you used, all of the names will see the same change because they all refer to the same object. If you change name binding by reassigning a different object to one name, the other names will not be effected.

Analogy: you might be known by many different names: “John”, “Johnny”, “Johnno”, “son”, “Mister M.”, “dad”, “boss”, “Hey you!” etc. If “John” gets a tattoo or a haircut, so will “Johnno” and all the others, because they’re just different names for the same person. But if your staff change jobs, so that “boss” now refers to me instead of you, my haircut won’t show up on “John” and “Johnny” etc.

2 Likes