更改字典中的列表将更改所有列表

2024-10-01 04:59:21 发布

您现在位置:Python中文网/ 问答频道 /正文

我在这里读过这些帖子,它们准确地解释了我面临的问题,但没有一个解决方案是有效的:

Changing one list unexpectedly changes another, too

Changing One dict value changes all values

我有一个特定形状的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相同的对象,但没有。正如您在我的代码中所看到的,我使用newlist = list(oldlist)创建单独的列表。我也试过newlist = oldlist[:]newlist = oldlist.copy()等等

我错过了什么


Tags: infalsetrue列表for字典statusrange
3条回答
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)

你和副本很接近,但实际上你需要一份深度副本

您可以看到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]]}

现在,您可以在不影响其他元素的情况下更改任何元素

正如我前面所说,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]]}

相关问题 更多 >