pythonpython-3.xlist

deep copy of list in python


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]]

Solution

  • 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)