提问人:Coder1913 提问时间:3/14/2023 更新时间:3/14/2023 访问量:32
列表推导的存储位置问题
Stored Location Issue With List Comprehensions
问:
我正在尝试用 Python 编写一个函数来创建一个具有指定维度的游戏板。这个想法是将板表示为嵌套列表,每个空格的初始值相同(并在函数的输入中指定)。为此,我编写了以下代码:
def make_board(dimensions, val, lst = []):
if not dimensions:
return lst
elif len(dimensions) == 1 and not lst:
return [val for i in range(dimensions[0])]
elif len(dimensions) == 1 and lst:
return [lst.copy() for i in range(dimensions[0])]
else:
if not lst:
new_lst = [val for i in range(dimensions[-1])]
else:
new_lst = [lst.copy() for i in range(dimensions[-1])]
return make_board(dimensions[:-1], val, new_lst)
当我最初制作电路板时,这运行良好。但是,如果我随后尝试更新其中一个空间,我会遇到它更新多个空间的问题。例如,当我运行以下命令时,我会得到以下结果:
example = make_board((2, 4, 2), 0)
print(example)
>>> [[[0, 0], [0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0], [0, 0]]]
example[1][3][0] = 4
>>> [[[0, 0], [0, 0], [0, 0], [4, 0]], [[0, 0], [0, 0], [0, 0], [4, 0]]]
出于某种我不明白的原因,似乎我在函数中的列表推导将值/列表存储在同一地址。具体来说,当我遍历长度为 2 的 8 个内部列表并打印十六进制 ID 时,对于相应的索引,十六进制 ID 是相同的(因此 example[0][0] 与 example[1][0] 具有相同的十六进制 id,依此类推)。
我注意到的一件事是,最初当我尝试将值更改为 4 时,我得到了 [[[4, 0], [4, 0], [4, 0], [4, 0]], [[4, 0], [4, 0], [4, 0], [4, 0]]]。当我在上面的函数中将 .copy() 添加到两个 lst 实例时,它对其进行了更改,以便只有一个重复项。但是,我对从这里开始去哪里感到困惑。我以前没有遇到过列表推导的问题,因此关于我还可以做些什么来尝试故障排除的任何建议将不胜感激。
当我最初制作电路板时,这运行良好。但是,如果我随后尝试更新其中一个空间,我会遇到它更新多个空间的问题。例如,当我运行以下命令时,我会得到以下结果:
example = make_board((2, 4, 2), 0)
print(example)
>>> [[[0, 0], [0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0], [0, 0]]]
example[1][3][0] = 4
>>> [[[0, 0], [0, 0], [0, 0], [4, 0]], [[0, 0], [0, 0], [0, 0], [4, 0]]]
出于某种我不明白的原因,似乎我在函数中的列表推导将值/列表存储在同一地址。具体来说,当我遍历长度为 2 的 8 个内部列表并打印十六进制 ID 时,对于相应的索引,十六进制 ID 是相同的(因此 example[0][0] 与 example[1][0] 具有相同的十六进制 id,依此类推)。
我注意到的一件事是,最初当我尝试将值更改为 4 时,我得到了 [[[4, 0], [4, 0], [4, 0], [4, 0]], [[4, 0], [4, 0], [4, 0], [4, 0]]]。当我在上面的函数中将 .copy() 添加到两个 lst 实例时,它对其进行了更改,以便只有一个重复项。但是,我对从这里开始去哪里感到困惑。我以前没有遇到过列表推导的问题,因此关于我还可以做些什么来尝试故障排除的任何建议将不胜感激。
答:
x.copy() 返回 x 的浅拷贝(即它构造一个新列表,其中包含对原始列表中元素的引用)--相反,使用 copy.deepcopy(),递归地将原始列表中包含的元素的对象复制到新列表中,应该对你有用:
import copy
def make_board(dimensions, val, lst=[]):
if not dimensions:
return lst
elif len(dimensions) == 1 and not lst:
return [val for _ in range(dimensions[0])]
elif len(dimensions) == 1 and lst:
return [copy.deepcopy(lst) for _ in range(dimensions[0])]
else:
if not lst:
new_lst = [val for _ in range(dimensions[-1])]
else:
new_lst = [copy.deepcopy(lst) for _ in range(dimensions[-1])]
return make_board(dimensions[:-1], val, new_lst)
example = make_board((2, 4, 2), 0)
example[1][3][0] = 4
print(example)
这将返回
[[[0, 0], [0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0], [4, 0]]]
评论