提问人:SquiggleCat 提问时间:9/29/2023 最后编辑:SquiggleCat 更新时间:9/30/2023 访问量:65
为什么更改一个 Python 列表元素会更改所有其他元素?
Why does changing one Python list element change all the others?
问:
我有一些代码,我制作了一个字典,每个值都是列表。我发现递增任何列表索引都会递增每个值的相应索引;即 将递增彼此列表的 0 索引。[0,0]
d[key][0] += 1
我认为 Python 对列表的浅层复制是罪魁祸首,因为我的字典是使用 .但是,我在列表中使用时遇到了同样的问题。
然后我尝试了字典理解:.这正如我所期望的那样工作;修改一个列表不会影响其他列表。dict.fromkeys(keys, [0,0])
copy.deepcopy
{key:[0,0] for key in keys}
既然我已经找到了解决这个问题的方法,我的实际问题是为什么会这样。似乎要么我对工作原理有误解,要么与手头的问题无关,但我不知道还有什么会导致这种情况。deepcopy
这是一个完整的代码片段,重现了以下行为:
import copy
keys = [i for i in range(5)]
l = [0,0]
d = dict.fromkeys(keys, copy.deepcopy(l))
#d = {key:[0,0] for key in keys} # this approach works as expected
d[0][0] += 1
print(d)
# expected: {0: [1, 0], 1: [0, 0], 2: [0, 0], 3: [0, 0], 4: [0, 0]}
# actual: {0: [1, 0], 1: [1, 0], 2: [1, 0], 3: [1, 0], 4: [1, 0]}
答:
您只制作列表的一个副本,并将其用于字典中的每个值。函数参数仅计算一次,结果将传递给函数。所以当你写
d = dict.fromkeys(keys, copy.deepcopy(l))
它实际上等同于
temp = copy.deepcopy(l)
d = dict.fromkeys(keys, temp)
请改用字典推导式,以便为每个元素创建一个新副本。
d = {key: copy.deepcopy(l) for key in keys}
在这种情况下,对问题没有帮助,而是功能。
来自 https://docs.python.org/3/library/stdtypes.html#dict.fromkeys 的文档deepcopy
dict.fromkeys
所有值都仅引用单个实例,因此值通常是可变对象(如空列表)是没有意义的。若要获取非重复值,请改用字典推导式。
您将为值参数传递单个列表。因此,字典中的每个键都引用了一个列表,该列表恰好是从 中深度复制的。fromkeys
l
因此,您的词典理解似乎是推荐的方法。由于您正在为每个元素创建一个新列表,因此 ,它们保持独立。[0, 0]
我会以不同的方式制作字典。这里真的没有必要。copy.deepcopy
keys = list(range(5))
values = [[0,0] for _ in keys]
d = dict(zip(keys, values))
#one-liner: d = {k:[0,0] for k in range(5)}
d[0][0] += 1
print(d) #{0: [1, 0], 1: [0, 0], 2: [0, 0], 3: [0, 0], 4: [0, 0]}
评论
f(a, b)
b
dict.fromkeys(keys, [0,0])
copy.deepcopy(l)
dict.fromkeys(keys, [0,0])
[0, 0]
)