当前位置: 代码迷 >> python >> 字典中的Python更改列表更改所有列表(没有其他解决方案工作)
  详细解决方案

字典中的Python更改列表更改所有列表(没有其他解决方案工作)

热度:54   发布时间:2023-07-16 09:43:04.0

我花了3个小时在这里阅读帖子,解释了我遇到的问题,但没有一个解决方案正在发挥作用。

这些帖子不起作用:

我有一个python模块,我有一个特定形状的2D数组我需要初始化字典中的条目。 我是这样做的:

empty = []
for x in range(2):
    empty.append([])
    for y in range(2):
        empty[x].append(False)

status = {k:[] for k in ["a", "b", "c"]}

status["a"] = list(empty)
status["b"] = list(empty)
status["c"] = list(empty)

print(status)
status["a"][0][0] = True
print(status)

(例如简化列表的形状)

这打印:

{'a': [[False, False], [False, False]], 'b': [[False, False], [False, False]], 'c': [[False, False], [False, False]]}
{'a': [[True, False], [False, False]], 'b': [[True, False], [False, False]], 'c': [[True, False], [False, False]]}

如您所见,设置其中一个列表值会更改所有列表。 我不希望这样,我希望它们是具有不同值的单独列表(在一个字典中)。 最初,我以为我已经完成了旧的newlist = oldlist错误,我将newlist设置为与oldlist相同的对象,但是nope。 正如您在我的代码中看到的那样,我使用newlist = list(oldlist)制作单独的列表。 我也试过newlist = oldlist[:]newlist = oldlist.copy()等等。

我错过了什么? 非常感谢你花时间看这个问题,我很感激任何意见。

from copy import deepcopy
empty = []
for x in range(2):
    empty.append([])
    for y in range(2):
        empty[x].append(False)

status = {k:[] for k in ["a", "b", "c"]}

status["a"] = deepcopy(empty)
status["b"] = deepcopy(empty)
status["c"] = deepcopy(empty)

print(status)
status["a"][0][0] = True
print(status)

你接近副本,但实际上你需要深刻的复印件

正如我之前所说, list(empty) 确实创建了一个新列表,但是新列表的内部列表只是对empty的相同列表对象的引用。

可以使用 ,但我认为只在需要时构建新列表更简单。 deepcopy函数跳过各种箍,这些箍是复制可以包含任何内容的任意深嵌套对象所必需的。 但是,当你有一个从头开始构建简单的结构时,为什么还要经历所有这些事情呢?

使用列表推导,您的代码可以这样编写:

status["a"] = [[False] * 2 for _ in range(2)]
status["b"] = [[False] * 2 for _ in range(2)]
#etc

为最里面的列表做[False] * 2是安全的:共享不可变对象(布尔值,整数,字符串等)总是安全的。 只有当您意外地共享可变对象并且您改变其值而不是用新对象替换它时,才会出现此问题。

为避免重写该列表comp,您可以使用函数为您构建列表。 例如,

def empty(rows, columns):
    return [[False] * columns for _ in range(rows)]

status = {key: empty(2, 2) for key in 'abc'}
print(status)
status["a"][0][0] = True
print(status)

产量

{'a': [[False, False], [False, False]], 'b': [[False, False], [False, False]], 'c': [[False, False], [False, False]]}
{'a': [[True, False], [False, False]], 'b': [[False, False], [False, False]], 'c': [[False, False], [False, False]]}

您可以看到empty列表的第一个元素在字典中的所有值之间共享:

>>> id(empty[0]) == id(status['a'][0]) == id(status['b'][0]) == id(status['c'][0])
True

它们各自共享相同的内存位置。 对于空列表中的第二项也是如此, id(empty[1]) == id(status['a'][1]) == ...

这样做的原因是您将empty列表分配给每个值。 您可以对此空的嵌套列表执行深层复制,也可以使用列表推导为字典中的每个键生成新的列表。 对列表创建的列表理解本身是在字典理解中完成的,以便为所有必需的键生成status变量。

empty_rows = 2
empty_cols = 2
keys = ['a', 'b', 'c']
status = {k: [[False] * empty_cols 
              for _ in range(empty_rows)] 
          for k in keys}

# Example usage:
status['a'][0][0] = True
>>> status
{'a': [[True, False], [False, False]],
 'b': [[False, False], [False, False]],
 'c': [[False, False], [False, False]]}

现在您可以更改任何元素,而不会影响其他元素。

我认为您需要的是深层复制,请参阅文档

import copy
empty = []
for x in range(2):
    empty.append([])
    for y in range(2):
        empty[x].append(False)

status = {k:[] for k in ["a", "b", "c"]}

status["a"] = copy.deepcopy(empty)
status["b"] = copy.deepcopy(empty) 
status["c"] = copy.deepcopy(empty)
status['a'][0][0] = True
print(status)
  相关解决方案