1

I have a list named MyList. I want to copy the list to a new one, then add items to the new one, so I do:

MySecondList=MyList

for item in MyList:
    if item==2:
        MySecondList.append(item)

The problem I am having is that the items will be added also to MyList, and as a matter of fact the loop keeps going through MyList new items too!!

Is that normal? why does it happen? shouldnt the iteration use only the original list MyList for it, instead of dinamically increase with the items I add to other list?

I want badges
  • 6,155
  • 5
  • 23
  • 38

2 Answers2

1

Yes, it is normal as lists are mutable in python and this operation:

MySecondList = MyList

simply creates a new reference to the same list object and list.append modifies the same object in-place.(other operations like +=, list.extend, list.pop etc also modify the list in-place)

You can use a shallow copy here:

MySecondList = MyList[:]

Demo:

>>> from sys import getrefcount
>>> lis = [1,2,3]
>>> foo = lis       #creates a new reference to the same object [1,2,3]
>>> lis is foo
True
>>> getrefcount(lis) #number of references to the same object
3                    #foo , lis and shell itself

#you can modify the list [1,2,3] from any of it's references
>>> foo.append(4)
>>> lis.append(5)
>>> foo,lis
([1, 2, 3, 4, 5], [1, 2, 3, 4, 5])

>>> lis = [1,2,3]
>>> foo = lis[:]    #assigns a shallow copy of lis to foo
>>> foo is lis
False
>>> getrefcount(lis) #still 2(lis + shell_, as foo points to a different object
2

#different results here
>>> foo.append(4)
>>> lis.append(5)
>>> foo, lis
([1, 2, 3, 4], [1, 2, 3, 5])

For a lists of lists(or list of mutable objects) a shallow copy is not enough as the inner lists(or objects) are just new references to the same object:

>>> lis = [[1,2,3],[4,5,6]]
>>> foo = lis[:]
>>> foo is lis              #lis and foo are different
False

>>> [id(x) for x in lis]    #but inner lists are still same 
[3056076428L, 3056076716L]
>>> [id(x) for x in foo]    #same IDs of inner lists, i.e foo[0] is lis[0] == True
[3056076428L, 3056076716L]
>>> foo[0][0] = 100         # modifying one will affect the other as well
>>> lis[0],foo[0]
([100, 2, 3], [100, 2, 3])

For such cases use copy.deepcopy:

>>> from copy import deepcopy
>>> lis = [[1,2,3],[4,5,6]]
>>> foo = deepcopy(lis)
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
0

Because they both reference the same list (and their ids are the same). Observe:

>>> a = [1,2,3]
>>> b = a
>>> b
[1, 2, 3]
>>> a is b
True
>>> b += [1]
>>> b
[1, 2, 3, 1]
>>> a
[1, 2, 3, 1]
>>> a is b
True

Do this instead:

MySecondList = MyList[:]

What this does is makes a copy of a list which won't change the original list. You can also use list(MyList).

TerryA
  • 58,805
  • 11
  • 114
  • 143