>>> x = 3
>>> y = x
>>> print(id(x), id(y))
9251744 9251744
>>> y = 4
>>> print(id(x), id(y))
9251744 9251776
>>> print(x,y)
3 4
>>>
Python creates only real copies, if it has to, i.e. if the user, the programmer, explicitly demands it.
>>> colors1 = ["red", "blue"]
>>> colors2 = colors1
>>> colors1
['red', 'blue']
>>> colors2
['red', 'blue']
>>> print(id(colors1), id(colors2))
139767907255944 139767907255944
>>> colors2 = ["rouge", "vert"]
>>> colors2
['rouge', 'vert']
>>> colors1
['red', 'blue']
>>> print(id(colors1), id(colors2))
139767907255944 139767907256072
>>>
>>> colors = ["red", "blue"]
>>> colors2 = colors
>>> print(id(colors), id(colors2))
139767907297288 139767907297288
>>> colors2[1] = "green"
>>> colors2
['red', 'green']
>>> colors
['red', 'green']
>>> print(id(colors), id(colors2))
139767907297288 139767907297288
>>>
The explanation is that we didn't assign a new object to colors2. We changed colors2 inside or as it is usually called "in-place". Both variables "colors" and "colors2" still point to the same list object.
It's possible to completely copy shallow list structures with the slice operator without having any of the side effects
>>> list1 = ['a', 'b', 'c', 'd']
>>> list2 = list1[:]
>>> list1
['a', 'b', 'c', 'd']
>>> list2
['a', 'b', 'c', 'd']
>>> list2[1] = 'popeyes'
>>> list1
['a', 'b', 'c', 'd']
>>> list2
['a', 'popeyes', 'c', 'd']
But as soon as a list contains sublists, we have another difficulty: The sublists are not copied but only the references to the sublists.
>>> lst1 = ['a', 'b', ['ab', 'ba']]
>>> lst2 = lst1[:]
>>> lst1
['a', 'b', ['ab', 'ba']]
>>> lst2
['a', 'b', ['ab', 'ba']]
>>> lst2[0] = 'Hello'
>>> lst1
['a', 'b', ['ab', 'ba']]
>>> lst2
['Hello', 'b', ['ab', 'ba']]
>>> lst2[2][1] = 'World'
>>> lst1
['a', 'b', ['ab', 'World']]
>>> lst2
['Hello', 'b', ['ab', 'World']]
>>>
A solution to the described problems provide the module "copy". This module provides the method "deepcopy", which allows a complete or deep copy of an arbitrary list, i.e. shallow and other lists.
>>> from copy import deepcopy
>>>
>>> lst1 = ['a','b',['ab','ba']]
>>>
>>> lst2 = deepcopy(lst1)
>>>
>>> lst1
['a', 'b', ['ab', 'ba']]
>>> lst2
['a', 'b', ['ab', 'ba']]
>>> id(lst1)
139716507600200
>>> id(lst2)
139716507600904
>>> id(lst1[0])
139716538182096
>>> id(lst2[0])
139716538182096
>>> id(lst2[2])
139716507602632
>>> id(lst1[2])
139716507615880
>>>
We can see by using the id function that the sublist has been copied, because id(lst2[2]) is different from id(lst1[2]). An interesting fact is that the strings are not copied: lst1[0] and lst2[0] reference the same string.
>>> lst2[2][1] = "d"
>>> lst2[0] = "c"
>>> print(lst1)
['a', 'b', ['ab', 'ba']]
>>> print(lst2)
['c', 'b', ['ab', 'd']]
>>>
This is true for lst1[1] and lst2[1] as well, of course.