每次迭代字典列表只会保留最后添加的值

6
我有一个字典列表:
```python ```
MylistOfdict = [
    {'Word': 'surveillance',
     'Word No': 1},
    {'Word': 'equivocal',
     'Word No': 2}]

我希望创建一个新的字典列表(word_db2),其中每个字典都由MylistOfdict中的一个字典生成,并且除了包含MylistOfdict的键和值之外,每个字典还应该有一个'卡类型'键和值分别为Type 1、Type 2、Type 3,以及一个'卡密钥'键并带有递增值。
代码:
word_db2 = []

key = 1
for i in MylistOfdict:
    for j in range(1, 4):
        i['Card Type'] = 'Type ' + str(j)
        i['Card Key'] = key
        print(i)
        
        word_db2.append(i)
        key += 1

输出:

{'Word': 'surveillance', 'Word No': 1, 'Card Type': 'Type 1', 'Card Key': 1}
{'Word': 'surveillance', 'Word No': 1, 'Card Type': 'Type 2', 'Card Key': 2}
{'Word': 'surveillance', 'Word No': 1, 'Card Type': 'Type 3', 'Card Key': 3}
{'Word': 'equivocal', 'Word No': 2, 'Card Type': 'Type 1', 'Card Key': 4}
{'Word': 'equivocal', 'Word No': 2, 'Card Type': 'Type 2', 'Card Key': 5}
{'Word': 'equivocal', 'Word No': 2, 'Card Type': 'Type 3', 'Card Key': 6}

这个输出是正确的,但是word_db2在每次迭代中只存储最后添加的值:
[{'Word': 'surveillance', 'Word No': 1, 'Card Type': 'Type 3', 'Card Key': 3},
 {'Word': 'surveillance', 'Word No': 1, 'Card Type': 'Type 3', 'Card Key': 3},
 {'Word': 'surveillance', 'Word No': 1, 'Card Type': 'Type 3', 'Card Key': 3},
 {'Word': 'equivocal', 'Word No': 2, 'Card Type': 'Type 3', 'Card Key': 6},
 {'Word': 'equivocal', 'Word No': 2, 'Card Type': 'Type 3', 'Card Key': 6},
 {'Word': 'equivocal', 'Word No': 2, 'Card Type': 'Type 3', 'Card Key': 6}]

4
请复制字典而不是重复使用同一个字典。在for j in range(1, 4):的内部循环的第一行中添加i = dict(i)。另外,i是字典的不好的名称,按照约定,应该称其为d,因为i通常表示整数。 - Steven Rumbalski
与 https://dev59.com/XXE85IYBdhLWcg3wyGp_ 相同的问题,但是这次针对的是字典而不是列表。 - Karl Knechtel
4个回答

6

让我们逐步审查循环体逻辑:

  1. 选取其中一个字典
  2. 修改它
  3. 将其附加到列表末尾

因此,你忽略的关键点是,修改和附加是相同的对象,该对象是在第一步选择的。在代码段结束时,word_db2 包含六个对象引用,但只有两个是唯一的。因此,输出显示相似的行。

在修改和添加之前,你可以对字典进行 浅复制

for j in range(1, 4):
    i = dict(i)
    i['Card Type'] = 'Type '+str(j)
    i['Card Key'] = key
    print(i)

    word_db2.append(i)
    key += 1

作为进一步的说明,如果字典包含其他可变对象,例如嵌套字典,您应该进行深拷贝
import copy
old_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}
new_dict = copy.deepcopy(old_dict)
old_dict['a'][1] = 7
new_dict['a'][1] # 2

4
当您将字典附加到列表中时,附加的是对原始对象本身的引用。因此,在内部循环的每次迭代中,您当前只是修改现有对象的键和值,因此最后写入的值是唯一持久存在的东西。
要实现您需要的功能,您需要在内部循环的每次迭代中创建一个新的字典对象。对于MylistOfdict中显示的字典,简单的字典推导式即可解决问题。但如果您有更复杂的字典,请使用copy模块的深层复制方法。
MylistOfdict = [{'Word': 'surveillance', 'Word No': 1}, 
                {'Word': 'equivocal', 'Word No': 2}]
word_db2 = []

key = 1
for i in MylistOfdict:
    for j in range(1, 4):
        # Creating a new dictionary object and copying keys and values from i
        new_dict = {k: v for k, v in i.items()}
        new_dict['Card Type'] = 'Type '+str(j)
        new_dict['Card Key'] = key

        print(new_dict)

        word_db2.append(new_dict)
        key += 1

1

不要使用同一个字典,而是复制它们:

word_db2 = []

key = 1
for i in MylistOfdict:
    for j in range(1, 4):
        i = dict(i)
        i['Card Type'] = 'Type '+str(j)
        i['Card Key'] = key
        print(i)

        word_db2.append(i)
        key += 1

-1
使用深拷贝。发生的情况是,您的附加调用只是附加到原始对象的引用。
from copy import deepcopy

my_list_of_dict = [{'Word': 'surveillance',
                    'Word No': 1},
                   {'Word': 'equivocal',
                    'Word No': 2}]
word_db2 = []

key = 1
for i in my_list_of_dict:
    for j in range(1, 4):
        i['Card Type'] = 'Type ' + str(j)
        i['Card Key'] = key
        print(i)
        word_db2.append(deepcopy(i))
        key += 1


for i in word_db2:
    print(i)

好主意,但请注意在复制之前所选对象(i)仍被修改。因此,您应该先复制再进行修改。请编辑代码片段。 - Oleh Rybalchenko
不必要使用deepcopy,浅拷贝就足够了。制作字典的浅拷贝最简单的方法是将其传递给dict(例如copy_of_d = dict(d))。此外,在修改后进行复制会改变MylistOfdict的内容,这可能是一个不想要的副作用。为避免这种情况,应在内部循环的顶部进行复制。 - Steven Rumbalski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接