We can see what's happening if we get the id() of the lists:
test_list = []
print(id(test_list)) # output: 2280241512512
We have created a new list, called test_list, and its unique object id is shown above.
Now, we want to make a new list and add it into test_list. We'll call this list a, and get its id() which shows that it is a separate object:
a = [1,2]
print(id(a)) # output: 2280241515456
Once we've appended it to test_list, we can see that its contents are indeed there:
test_list.append(a)
print(test_list) # output: [[1, 2]]
So, if we loop through test_list, we can see the id() of the objects inside the list - and since we only added one item, a, we should expect to see its id there:
for item in test_list:
print(id(item)) # output: 2280241515456
Indeed we do see the same id from earlier. So, we know the object a is referenced inside test_list. So, what happens if we clear a?
a.clear()
print(test_list) # output: [[]]
We have cleared out a, and since it is referenced inside test_list, we can see the change reflected. And if we get the id of the objects inside test_list, we can see that it's still the same object, a:
print(id(test_list[0])) # output: 2280241515456
But, what if we want a copy of a's data, rather than a itself, to go into test_list? There's multiple ways to go about it, but using the a[:] syntax is a quick shortcut.
test_list = []
a = [1,2]
print(id(a)) # output: 1707726818240
test_list.append(a[:])
print(test_list) # output: [[1, 2]]
for item in test_list:
print(id(item)) # output: 1707729293952
a.clear()
print(a) # output: []
print(test_list) # output: [[1, 2]]
So, as we can see, using a[:] creates a copy of that list, and puts the copy into test_list, so that if we mess with a, the data in test_list is not affected.