3

I have a simple code as below:

def swap(node):
    m00         = node[0][0]
    node[0][0]  = node[1][0]
    node[0][1]  = m00

originalList = [[1,2,3], [4,5,6], [7,8,9]]

# temp = list(originalList)
temp = originalList[:]

swap(temp)

print originalList

Initially I define a list with the values shown above and then copy this list to a temporary one. I have tried both methods of copying. Then I perform a swap function using temp list and print the original list again. As a result the original list is changed. What's the reason behind this behavior?

user3764893
  • 697
  • 5
  • 16
  • 33
  • "both methods of copying": What would those be? – Scott Hunter Nov 13 '15 at 21:53
  • `originalList[:]` _does_ create a new copy of `originalList`. But it _doesn't_ create new copies of the lists inside `originalList`. – PM 2Ring Nov 13 '15 at 21:54
  • using `temp = list(originalList)` and `temp = originalList[:]` – user3764893 Nov 13 '15 at 21:54
  • 2
    In short: You create a copy of `originalList`, but not of the three lists contained in it (i.e., a shallow copy). Also see: [`copy.deepcopy()`](https://docs.python.org/2/library/copy.html#copy.deepcopy) – Lukas Graf Nov 13 '15 at 21:55
  • 1
    FWIW, you can simplify your `swap` by using tuple assignment: `node[0][0], node[0][1] = node[1][0], node[0][0]`. – PM 2Ring Nov 13 '15 at 21:59
  • http://stackoverflow.com/questions/17246693/what-exactly-is-the-difference-between-shallow-copy-deepcopy-and-normal-assignm – en_Knight Nov 13 '15 at 22:00
  • 1
    Also see http://stackoverflow.com/questions/240178/python-list-of-lists-changes-reflected-across-sublists-unexpectedly – PM 2Ring Nov 13 '15 at 22:04

2 Answers2

5

The way you are copying the list (both ways) is known as a shallow copy. This can be better seen this way:

l1 = [1,2,3]
l2 = [4,5,6]
l3 = [7,8,9]
originalList = [l1,l2,l3]
temp = originalList[:]
l1[0] = 0

>>> temp
[[0, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> originalList
[[0, 2, 3], [4, 5, 6], [7, 8, 9]]

When you make a shallow copy of originalList, you are still getting references to l1, l2, and l3. Any changes you make to those smaller lists will be reflected in both originalList and any shallow copies you make. You want a deep copy operation. For your purposes, Scott Hunter's answer of

temp = [x[:] for x in originalList]

will work. In the general case, the method deepcopy from the copy module should get you a deep copy of whatever objects you need. It is still likely better to use in this case as it is a few orders of magnitude faster.

Blair
  • 6,623
  • 1
  • 36
  • 42
3

originalList[:] makes a copy of the outer list, but the 3 shorter lists. You could make copies of them like so:

temp = [x[:] for x in originalList]
Scott Hunter
  • 48,888
  • 12
  • 60
  • 101