7

CODE IN PYCHARM

[1]: https://i.sstatic.net/aBP1r.png

I tried to make a deep copy of a list l, but seems like the slicing method doesn't work somehow?I don't want the change in x to be reflected in l. So how should I make a deep copy and what is wrong in my code?

This was my code-

def processed(matrix,r,i):
    matrix[r].append(i)
    return matrix

l=[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
x=l[:]
print(processed(x,0,10))
print(l)

OUTPUT-

[[1, 2, 3, 10], [4, 5, 6], [7, 8, 9]]
[[1, 2, 3, 10], [4, 5, 6], [7, 8, 9]]
3
  • 2
    That is how shallow copies work. You created a copy of the outer list, but appended 10 to the inner list, which is the same object in both lists, x and l. Commented Aug 22, 2020 at 5:45
  • Agreed, if you were expecting a different outcome then you're actually looking for a deep copy (one where the inner lists are unique objects). Commented Aug 22, 2020 at 5:48
  • In case of shallow copy, a reference of object is copied in other object. It means that any changes made to a copy of object do reflect in the original object. so, you get the same output. Commented Aug 22, 2020 at 5:54

3 Answers 3

12

Your code does indeed succeed in creating a shallow copy. This can be seen by inspecting the IDs of the two outer lists, and noting that they differ.

>>> id(l)
140505607684808

>>> id(x)
140505607684680

Or simply comparing using is:

>>> x is l
False

However, because it is a shallow copy rather than a deep copy, the corresponding elements of the list are the same object as each other:

>>> x[0] is l[0]
True

This gives you the behaviour that you observed when the sub-lists are appended to.

If in fact what you wanted was a deep copy, then you could use copy.deepcopy. In this case the sublists are also new objects, and can be appended to without affecting the originals.

>>> from copy import deepcopy

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

>>> xdeep = deepcopy(l)

>>> xdeep == l
True

>>> xdeep is l
False     <==== A shallow copy does the same here

>>> xdeep[0] is l[0]
False     <==== But THIS is different from with a shallow copy

>>> xdeep[0].append(10)

>>> print(l)
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

>>> print(xdeep)
[[1, 2, 3, 10], [4, 5, 6], [7, 8, 9]]

If you wanted to apply this in your function, you could do:

from copy import deepcopy

def processed(matrix,r,i):
    new_matrix = deepcopy(matrix)
    new_matrix[r].append(i)
    return new_matrix

l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
x = processed(l,0,10)
print(x)
print(l)

If in fact you know that the matrix is always exactly 2 deep, then you could do it more efficiently than using deepcopy and without need for the import:

def processed(matrix,r,i):
    new_matrix = [sublist[:] for sublist in matrix]
    new_matrix[r].append(i)
    return new_matrix

l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
x = processed(l,0,10)
print(x)
print(l)
Sign up to request clarification or add additional context in comments.

Comments

1

What you're looking for is a deeper copy than what you did. A shallow copy only replaces the top layer, which does not seem to be what you're looking for. If you wanted a different outcome, try something like this:

def processed(matrix,r,i):
    matrix[r] = [*matrix[r], i]
    return matrix

l=[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
x=l[:]
print(processed(x,0,10))
print(l)

The difference is that this makes two shallow copies - first to copy the outer list, and then the function copies the inner list before modifying it. The downside of this approach is that every call to processed now has extra overhead. If you wanted to do the copying all at once, you can do this:

def processed(matrix,r,i):
    matrix[r].append(i)
    return matrix

l=[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
x=[inner[:] for inner in l]
print(processed(x,0,10))
print(l)

This copies two layers deep, using list comprehensions. Your structure only has two layers, so this fully copies the list.

Comments

1

A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original. Whereas a deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

So you need to go for the deep copy for what you are expecting

from copy import deepcopy

l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
x = deepcopy(l)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.