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

Python Changing List in Dictionary Changes All Lists (no other solutions working)

在过去的3个小时里,我一直在这里阅读文章,准确地解释我遇到的问题,但是没有一个解决方案起作用。

这些职位不起作用:

更改一个列表也会意外地更改另一个列表

更改一个dict值将更改所有值

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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)

(例如,简化列表形状)

印刷品:

1
2
{'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()等。

我错过了什么?非常感谢您花时间仔细研究这个问题,我很感谢您的任何意见。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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,但我认为在你需要的时候创建新的列表更简单。deepcopy函数跳过了复制任意深度嵌套对象(可以包含任何内容)所需的各种环。但是当你有一个简单的从头开始构建的结构时,为什么还要费心去研究所有这些东西呢?

使用列表理解,可以这样编写代码:

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

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

为了避免重新编写列表组件,可以使用函数为您构建列表。如,

1
2
3
4
5
6
7
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)

输出

1
2
{'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]]}


可以看到,EDOCX1[0]列表的第一个元素在字典中的所有值中共享:

1
2
>>> 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变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
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]]}

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


我认为你需要的是一份深入的副本,请参阅copy.deepcopy()的文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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)