5

I am old and have no hair left to pull out. I have read as many answers to similar questions as I can find on SO. I have the following code:

a = [[1,2],[3,4],[4,5]]
b = ['a','b','c']
print('a:',a)
print('b:',b)
c = a[:]
print('c == a:', c==a)
print('c is a:',c is a)
print('id(c) = id(a):', id(c)==id(a))
[x.extend(b) for x in c]
print('c after:',c)
print('a after:',a)`

Output is:

a: [[1, 2], [3, 4], [4, 5]]
b: ['a', 'b', 'c']
c == a: True
c is a: False
id(c) = id(a): False
c after: [[1, 2, 'a', 'b', 'c'], [3, 4, 'a', 'b', 'c'], [4, 5, 'a', 'b', 'c']]
a after: [[1, 2, 'a', 'b', 'c'], [3, 4, 'a', 'b', 'c'], [4, 5, 'a', 'b', 'c']]

I am looking for the result shown as 'c after:' but I do not understand why a is modified, too?! I also tried

c = list(a)

and

c = copy.copy(a)

Of course, simple c = a does not work as expected. What am I missing?! Thank you.

Dave
  • 61
  • 8

4 Answers4

7

This is because you do not copy the elements inside the list. Lists inside a are not copied. Therefore your extend method affects elements inside both lists. You should use c = copy.deepcopy(a) in order to copy nested elements.

Piotr Dabkowski
  • 5,661
  • 5
  • 38
  • 47
1

try assigning c list like this,(without .copy() solution)

c = []
for elem in a:
    c.append(list(elem))

or one liner with list comprehension

c = [list(elem) for elem in a]

This supplies deep copy if you have list inside a list, not 3 layers of course.

The reason what you did failed is you managed to copy out list properly but the lists inside still refenced to same memory value, therefore there was no copy in element lists. This solution also copies inside lists, which is the definition of deepcopy.

Rockybilly
  • 2,938
  • 1
  • 13
  • 38
0

As the other posters explained, the lists inside A are not actually copied to C - they're just references to the original ones. You can see that when you run the code below:

num_lists = [[1,2],[3,4],[4,5]]
lists_copy = num_lists[:]

orig_first = num_lists[0]
copy_first = lists_copy[0]

print('Are the first elements the same object?', orig_first is copy_first)

Which prints "True", meaning that the [1,2] inside lists_copy is actually the [1,2] from num_lists. Copying Python lists is far too complicated and I hope they change it to be more friendly in the future. As of now, the best you can do is: lists_copy = copy.deepcopy(num_lists)

You can see it work below:

from copy import deepcopy

lists_copy = deepcopy(num_lists)

orig_first = num_lists[0]
copy_first = lists_copy[0]

print('Are they they the same after copying with deepcopy?', orig_first is copy_first)

This code prints "False", meaning the list is safely copied and balance is finally restored to the universe : )

uryga
  • 402
  • 4
  • 14
0

Consider also that lists are mutable types which can be modified after creation in contrast to immutable types such as strings for example. Immutable types cannot be changed after their creation. Therefore, a real copy of a string is made if you would try to append a second string to it. Mutable types can be changed. Hence, no copy is made and both a and c reference the same list.