为啥附加到列表的值会动态变化?

Posted

技术标签:

【中文标题】为啥附加到列表的值会动态变化?【英文标题】:Why does value appended to list change dynamically?为什么附加到列表的值会动态变化? 【发布时间】:2022-01-08 01:09:55 【问题描述】:

Python 版本:3.9.5

我的代码:

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)

实际输出:

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

预期输出:

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

我每次都在外部循环中更改列表 cells 的值,并将修改后的列表附加到 steps 列表中。正如您在输出中看到的那样,在第二次迭代中,cells 的第一个元素也被修改了,即使我只是将一个元素附加到列表中。

steps 的第一个元素是上一次迭代的cells 列表。但是在第二次迭代中,两个元素都会动态变化,即使我只是附加一个元素,所以第一个元素不应该受到影响。

为什么会发生这种情况以及如何克服?

【问题讨论】:

【参考方案1】:

list(cells)创建一个浅拷贝,因此修改cells的可变内容也会改变浅拷贝的内容——或者说,浅拷贝的内容真的是同一个对象 作为cells的内容。

你想要的是一个深拷贝:

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)

输出:

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

我已将 random.randint 部分替换为静态值,因此演示的输出更少……随机。

【讨论】:

【参考方案2】:

列表被原地操作

这是因为列表是通过对磁盘上真实对象(存储位置)的引用来操作的。请参阅以下示例:

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

您可以通过使用新变量或 copy.deepcopy() 来克服这个问题

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

【讨论】:

以上是关于为啥附加到列表的值会动态变化?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 GL_MAX_UNIFORM_BLOCK_SIZE 的值会发生变化?

为啥我的数组值会发生变化? [复制]

在 Jupyter Notebook 中使用 matplotlib 绘制动态变化的图形

前端动态效果 - dynamic

js动态获取下拉框的数据(搜索条件之间互相影响)

为啥内部值会对整个 ref 的变化做出反应?