0

This is a small piece of code and im trying to understand from past 3 hours, im getting Nowhere:

n =10
for i in range(3):
    a .insert(0,n+i)
    print('A =>',a)
    b.append(a)
    print('B=>', b)

The Output of the following code is :

A => [10]
B=> [[10]]
A => [11, 10]
B=> [[11, 10], [11, 10]]
A => [12, 11, 10]
B=> [[12, 11, 10], [12, 11, 10], [12, 11, 10]]

My Confusion is, when i'm inserting a new element in list a , and then appending the new list a to the old list b, why are the previous values getting overridden??? I cant understand , what is happening here

PyCoder
  • 9
  • 1
  • Hello PyCoder you can also have a look at this :) this is similar to the reason why that is happening [link](https://stackoverflow.com/questions/52642538/python-changing-list-in-dictionary-changes-all-lists-no-other-solutions-working/52642675) – Ice Bear Dec 21 '20 at 09:22
  • You keep appending *the same list* to `b` – juanpa.arrivillaga Dec 21 '20 at 09:37
  • Note, this behavior isn't unique to lists, **all objects work this way** when you `.append` them to a list – juanpa.arrivillaga Dec 21 '20 at 09:43

2 Answers2

0

This has to do with the way python copies lists.
When you do b.append(a) you are actually appending the reference of a, so when you change any value of a it will also change b:

Simplified depiction of what's happening:

# a = [] -> id_123 
# b = [] -> id_321 

a.insert(0,10)
# a = [10] --> id_123

b.append(a)
# b = [id123] = [[10]] --> id_321

a.insert(0,11)
# a = [10,11] --> id_123

b.append(a)
# b = [id123,id123] = [[10,11],[10,11]] --> id_321

In the end:

A => [12, 11, 10] --> id_123
B => [[12, 11, 10], [12, 11, 10], [12, 11, 10]] --> id_321

In the comments you have explained that you tried:

print(a is b)
# prints False

However, trying: a is b[0] will give the expected result(True):

for e in b:
    print(a is e)

#prints True 3 times

Finally, if you were aiming to instead obtain:

A => [10]
B=> [[10]]
A => [11, 10]
B=> [[10], [11, 10]]
A => [12, 11, 10]
B=> [[10], [11, 10], [12, 11, 10]]

Then, you can simply change the appending to b to:

b.append(a[:])

Here is a reference form another question here on SO: From List changes unexpectedly after assignment. How do I clone or copy it to prevent this?:

With new_list = my_list, you don't actually have two lists. The assignment just copies the reference to the list, not the actual list, so both new_list and my_list refer to the same list after the assignment.

Full code:

a=[]
b=[]
n =10
for i in range(3):
    a .insert(0,n+i)
    print('A =>',a)
    b.append(a[:])
    print('B=>', b)
willcrack
  • 1,794
  • 11
  • 20
  • 1
    If you are going to post a link to another answer, you should vote to close as a duplicate next time. – juanpa.arrivillaga Dec 21 '20 at 09:42
  • I can´t vote to close with my level of reputation. Instead I thought it would be cool to nudge the OP in the right direction while providing a link to useful information, and relating this to the duplicate. – willcrack Dec 21 '20 at 11:15
0

By appending a to b, you do not copy the object, but create a bindings between a and b. Since the list is mutable, you need a deepcopy, so you can change one without changing another.

import copy
n =10
b=[]
a = []
for i in range(3):
    a.insert(0,n+i)
    print('A =>',a)
    b.append(copy.deepcopy(a))
    print('B=>', b)
MrLukas
  • 167
  • 1
  • 12
  • hi MrLukas, so do u mean that both of the variables a and b are pointing to the same object?? But i even tried print(a is b) and it returned false, which means these object's are not same. isn't it? – PyCoder Dec 21 '20 at 09:41
  • You actually **do not need a deep copy here** – juanpa.arrivillaga Dec 21 '20 at 09:41
  • @PyCoder no. The list being referred to by `b` contains multiple references to the list being referred to by `a`. – juanpa.arrivillaga Dec 21 '20 at 09:42
  • im sorry junapa.arrivillaga , can you explain it in a little more?? – PyCoder Dec 21 '20 at 09:44
  • You have a list `a = [1, 2]`, let's say. You have another list, `b = []` You then do `b.append(a)`. Now **the second list contains the first list**. So obviously, if you mutate the first list, `a.append(3)` and then `print(a)` you see `[1,2,3]` but of course, since the second list *contains the first list* you see the same thing in the second list. Read the following: https://nedbatchelder.com/text/names.html – juanpa.arrivillaga Dec 21 '20 at 09:47