user
user

Reputation: 33

Cloning a list inside a function Python

def foo(image):
    res = image[:]
    for i in range(3):
        for j in range(3):
            res[i][j] = 1
    return image

foo([[0,0,0],[0,0,0],[0,0,0]])

For the above function, I copied the image to res and only modified res inside the function. So I assumed that calling the function should return the same as my input. However, the output is a 3 by 3 arrays with all ones. Could anyone explain this to me, please? Thanks.

I guess it is something related to local and global variables, but I am not sure. If I want to clone the image to res and only change the values for res, how am I supposed to manage it?

Upvotes: 0

Views: 116

Answers (2)

Arron Poucher
Arron Poucher

Reputation: 26

Solution

You're seeing this behaviour because res is a shallow copy of image.

To see the behaviour you expected you will need to create a deep copy instead, luckily the standard library includes a way to do this for simple cases.

import copy

def foo(image):
    res = copy.deepcopy(image)
    for i in range(3):
        for j in range(3):
            res[i][j] = 1
    return image

foo([[0,0,0],[0,0,0],[0,0,0]])

If you don't want to bring in another dependency, then you can get the same result with a list comprehension.


def foo(image):
    res = [x[:] for x in image]
    for i in range(3):
        for j in range(3):
            res[i][j] = 1
    return image

foo([[0,0,0],[0,0,0],[0,0,0]])

Explanation

Lists in python are by reference, not value, the same list can be accessed by different names.

We can see this by running the following:

import copy

original = [[1]]
shallow_copy = original[:]
deep_copy = copy.deepcopy(original)

shallow_copy[0][0] = 2

print(original)
print(deep_copy)

When you copy a list with image[:], python does the following:

  1. Creates a new list.
  2. For every item in image, add the same item to the new list.

It does not copy the internal lists, it just points to the original one.

As a result original and shallow_copy are different lists, but original[0] and shallow_copy[0] are the same list.

Upvotes: 1

itroulli
itroulli

Reputation: 2094

In your code res = image[:] creates a shallow copy of the res list. The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists, dicts, sets or class instances):

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

  • A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

So, in your code both res and image contain references to the same list objects.

[Source]

Upvotes: 1

Related Questions