What you've encountered is reference duplication in Python. To quote from copy module documentation:
Assignment statements in Python do not copy objects, they create bindings between a target and an object
You can observe how that works in practice if you think in terms of objects and their values, and use is
operator and id()
built-in function:
>>> a=1
>>> b=2
>>> c=a
>>> a is c
True
>>> id(a), id(c)
(10932288, 10932288)
>>> id(a), id(c)
Among other things you can verify exactly the same via references count:
>>> import sys
>>> a=1
>>> b=2
>>> sys.getrefcount(a)
803
>>> sys.getrefcount(b)
97
>>> c=a
>>> sys.getrefcount(c)
804
>>> sys.getrefcount(a)
804
>>> c=b
>>> sys.getrefcount(a)
803
>>> sys.getrefcount(b)
98
>>>
Tangentially, this is related to deep and shallow copying. Again from copy documentation:
The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances):
- A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.
- A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.
Your example uses simple variables and they will always default to reference duplication - no new objects no matter if you try to deep copy them:
>>> import copy
>>> id(b),id(c)
(10932320, 10932320)
>>> c = copy.deepcopy(b)
>>> id(b),id(c)
(10932320, 10932320)
However, if you try to assign tuples or lists, the story is different:
>>> a = [1,2,3]
>>> b = [3,2,1]
>>> c = a
>>> id(a),id(c)
(139967175260872, 139967175260872)
>>> c = copy.deepcopy(a)
>>> id(a),id(c)
(139967175260872, 139967175315656)
In the above example, you get an entirely different object. Why this might be useful ? The fact that simple assignment just makes two variables reference same object also implies that if you change one , changes get reflected in the other.
>>> id(c),id(a)
(139967175260872, 139967175260872)
>>> a.append(25)
>>> id(c),id(a)
(139967175260872, 139967175260872)
>>> c
[1, 2, 3, 25]
>>>
This can be impractical when you want to keep original data. When you want to have two same objects initially, but then let them change in their own way - that's where you want to have either shallow copy for just object itself or deep copy for all objects that are contained within the object:
>>> c = copy.deepcopy(a)
>>> a.append(35)
>>> a
[1, 2, 3, 25, 35]
>>> c
[1, 2, 3, 25]
And just for demo purposes, shallow copy:
>>> c = a
>>> a.append([9,8,7])
>>> a
[1, 2, 3, 25, 35, [9, 8, 7]]
>>> c = a
>>> id(a), id(c), id(a[-1])
(139967175260872, 139967175260872, 139967175315656)
>>> c = copy.copy(a)
>>> id(a), id(c), id(a[-1])
(139967175260872, 139967175315528, 139967175315656)
See also grc's excellent answer on the same topic with better examples.