字典中的Python更改列表会更改所有列表(其他解决方案无效)

时间:2018-10-04 08:42:29

标签: python python-3.x list

过去3个小时,我在这里阅读了帖子,确切地解释了我所遇到的问题,但是没有一种解决方案有效。

这些帖子无效:

Changing one list unexpectedly changes another, too

Changing One dict value changes all values

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

我想念什么?非常感谢您抽出宝贵的时间来研究这个问题,感谢您的投入。

4 个答案:

答案 0 :(得分:5)

var config =  Configuration.GetSection("MobileConfigInfo").Get<Dictionary<string, string>>(); 

您与副本关系密切,但实际上需要深拷贝

答案 1 :(得分:3)

正如我之前说的,curl -iX POST \ 'http://localhost:1026/v2/subscriptions' \ -H 'Content-Type: application/json' \ -H 'fiware-service: openiot' \ -H 'fiware-servicepath: /' \ -d '{ "description": "Notify Cygnus of all context changes", "subject": { "entities": [ { "idPattern": ".*" } ] }, "notification": { "http": { "url": "http://cygnus:5050/notify" }, "attrsFormat": "legacy" }, "throttling": 5 }' 确实创建了一个新列表,但是该新列表的内部列表只是对list(empty)中相同列表对象的引用。 / p>

可以使用deepcopy,但我认为,仅在需要时构建新列表比较简单。 empty函数会跳转各种复制任何包含任何内容的深层嵌套对象所需的各种箍。但是,当您拥有一个简单的从头开始构建的结构时,为什么还要烦恼所有这些事情呢?

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

deepcopy

对最里面的列表执行status["a"] = [[False] * 2 for _ in range(2)] status["b"] = [[False] * 2 for _ in range(2)] #etc 是安全的:共享不可变的对象(布尔值,整数,字符串等)始终是安全的。仅当您意外共享一个可变对象并且更改其值而不是将其替换为新对象时,才会出现此问题。

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

[False] * 2

输出

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)

答案 2 :(得分:2)

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

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

答案 3 :(得分:0)

我认为您需要的是深层副本,请参阅copy.deepcopy()的文档

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)