Home > OS >  Why does value appended to list change dynamically?
Why does value appended to list change dynamically?

Time:12-02

Python Version: 3.9.5

My Code:

cells = [[i, i] for i in range(3)]
steps = []

for t in range(2):
    for i in range(len(cells)):
        xrand = random.randint(-5, 5)
        yrand = random.randint(-5, 5)
        cells[i][0]  = xrand
        cells[i][1]  = yrand
    steps.append(list(cells))
    print(steps)

Actual Output:

[[[3, 3], [2, 3], [6, 3]]]
[[[4, 7], [-3, 2], [8, 3]], [[4, 7], [-3, 2], [8, 3]]]

Expected Output:

[[[3, 3], [2, 3], [6, 3]]]
[[[3, 3], [2, 3], [6, 3]], [[4, 7], [-3, 2], [8, 3]]]

I am changing the value of the list cells every time in the outer loop and appending the modified list to the steps list. As you can see in the output, in the second iteration, the first element of cells is also modified even though I am only appending an element to the list.

The first element of steps is the cells list from the previous iteration. But in the second iteration, both elements dynamically change even though I am only appending an element and so the first element shouldn't be affected.

Why does this happen and how do you overcome this?

CodePudding user response:

list(cells) creates a shallow copy, thus modifying the mutable content of cells will also mutate the contents of the shallow copy - or rather, the content of the shallow copy is really the same object as the content of cells.

What you want is a deep copy:

import copy

cells = [[i, i] for i in range(3)]
steps = []

for t in range(2):
    for i in range(len(cells)):
        xrand = 1
        yrand = 1
        cells[i][0]  = xrand
        cells[i][1]  = yrand
    steps.append(copy.deepcopy(cells))
    print(steps)

Output:

[[[1, 1], [2, 2], [3, 3]]]
[[[1, 1], [2, 2], [3, 3]], [[2, 2], [3, 3], [4, 4]]]

I have replaced the random.randint parts with static values, so the demonstrated output is less ... random.

CodePudding user response:

Lists are manipulated in place

This is because the list is manipulated with a reference to the real object (storage location) on the disk. See the following example:

l = [2]
x = [l, l]
print(x)
>>> [[2], [2]]
l[0] = 4
print(x)
>>> [[4], [4]]

You can overcome this by using either a new variable or a copy.deepcopy()

>>> import copy
>>> l = [2]
>>> x = [copy.deepcopy(l), l]
>>> print(x)
[[2], [2]]
>>> l[0] = 4
>>> print(x)
[[2], [4]]
  • Related