Python for循环中的dict()-不同的行为

Python for循环中的dict()-不同的行为,python,json,dictionary,for-loop,Python,Json,Dictionary,For Loop,我正在尝试使用for循环动态更新dict()键的值 def update_dict(): f = [] for i, j in enumerate(list_range): test_dict.update({'a': i}) j['c'] = test_dict print(j) f.append(j) print(f) test_dict = dict({'a': 1}) list_range = [{

我正在尝试使用for循环动态更新
dict()
键的值

def update_dict():
    f = []
    for i, j in enumerate(list_range):
        test_dict.update({'a': i})
        j['c'] = test_dict
        print(j)
        f.append(j)
    print(f)

test_dict = dict({'a': 1})
list_range = [{'b': i} for i in range(0, 5)]
update_dict()
甚至
print(j)
给出了迭代值
(0,1,2,3,4)
,不知何故,最后一个dict被覆盖到了整个列表,并给出了错误的输出
(4,4,4,4,4)

预期产量

[{'b': 0, 'c': {'a': 0}}, {'b': 1, 'c': {'a': 1}}, {'b': 2, 'c': {'a': 2}}, {'b': 3, 'c': {'a': 3}}, {'b': 4, 'c': {'a': 4}}]
获得的产出

[{'b': 0, 'c': {'a': 4}}, {'b': 1, 'c': {'a': 4}}, {'b': 2, 'c': {'a': 4}}, {'b': 3, 'c': {'a': 4}}, {'b': 4, 'c': {'a': 4}}]
我需要了解字典是如何被覆盖的,什么是避免这种情况的最佳解决方案

提前谢谢


注:请避免将列表或dict理解方法作为简单的答案,因为我知道它们,这个问题的唯一目的是理解dict()的错误行为

每次在循环中尝试向同一字典添加值,并且随着循环的进行,不断替换值

您需要在每次迭代中定义字典,以创建字典的单独引用:

def update_dict():
    f = []
    for i, j in enumerate(list_range):
        test_dict = {'a': i}
        j['c'] = test_dict
        f.append(j)
    print(f)


list_range = [{'b': i} for i in range(0, 5)]
update_dict()

# [{'b': 0, 'c': {'a': 0}}, 
#  {'b': 1, 'c': {'a': 1}},
#  {'b': 2, 'c': {'a': 2}},
#  {'b': 3, 'c': {'a': 3}},
#  {'b': 4, 'c': {'a': 4}}]

每次在循环中尝试向同一字典添加值,并且随着循环的进行,不断替换值

您需要在每次迭代中定义字典,以创建字典的单独引用:

def update_dict():
    f = []
    for i, j in enumerate(list_range):
        test_dict = {'a': i}
        j['c'] = test_dict
        f.append(j)
    print(f)


list_range = [{'b': i} for i in range(0, 5)]
update_dict()

# [{'b': 0, 'c': {'a': 0}}, 
#  {'b': 1, 'c': {'a': 1}},
#  {'b': 2, 'c': {'a': 2}},
#  {'b': 3, 'c': {'a': 3}},
#  {'b': 4, 'c': {'a': 4}}]

这种行为的原因是列表中的所有引用都指向同一个dict行
j['c']=test_dict
不会创建字典的副本,而只是使j['c']引用test_dict。要获得预期结果,需要将此行更改为:
j['c']=test_dict.copy()
。它将生成test_dict的深度副本并将其分配给j['c']。

这种行为的原因是列表中的所有引用都指向同一个dict。行
j['c']=test_dict
不创建字典的副本,而只是使j['c']引用test_dict。要获得预期结果,需要将此行更改为:
j['c']=test_dict.copy()
。它将对test dict进行深度复制,并将其分配给j['c']。

一个更简单的解决方案是迭代
列表范围
,并使用
b
中的值创建
c

lista = [{'b': i } for i in range(0, 5)]
for i in lista:
    i['c'] = {'a': i['b']}
# [{'b': 0, 'c': {'a': 0}}, {'b': 1, 'c': {'a': 1}}, {'b': 2, 'c': {'a': 2}}, {'b': 3, 'c': {'a': 3}}, {'b': 4, 'c': {'a': 4}}]

一个更简单的解决方案是迭代
list\u范围
,并使用
b
中的值创建
c

lista = [{'b': i } for i in range(0, 5)]
for i in lista:
    i['c'] = {'a': i['b']}
# [{'b': 0, 'c': {'a': 0}}, {'b': 1, 'c': {'a': 1}}, {'b': 2, 'c': {'a': 2}}, {'b': 3, 'c': {'a': 3}}, {'b': 4, 'c': {'a': 4}}]


test\u dict
对所有dict都是相同的。任何时候更新它都会更新所有的子目录。@Jean Françoisfab在调试时,我看到在每一次迭代中都有不同的值,但所有以前存储的值都会更改,因此目录。update()会更新列表中的所有值?
j['c']
不会创建任何新值,它指向一个对象,
test\u dict
。将它添加到脚本中,
j['c']=test_dict,id(test_dict)
并查看它是如何成为该函数之外的单个dict对象。
test_dict
对于所有dict都是相同的。任何时候更新它都会更新所有的子目录。@Jean Françoisfab在调试时,我看到在每一次迭代中都有不同的值,但所有以前存储的值都会更改,因此目录。update()会更新列表中的所有值?
j['c']
不会创建任何新值,它指向一个对象,
test\u dict
。将此添加到您的脚本中,
j['c']=test\u dict,id(test\u dict)
并查看它如何成为该函数之外的单个dict对象。您是对的,我的错,请查看您的代码可以简化!这个很好用。但是如果test_dict包含更多的键,比如
test_dict=dict({'a':1,'b':'c')
,而我不想更改'b'?那么您可以在循环中使用
test_dict={'a':i,'b':'c'}
b
的值始终是
c
。我所讨论的只是示例代码。在原始版本中,我的
test_dict
可能包含多个键,我需要更新其中的任何一个键。恐怕我不能在我的用例中使用你的建议。@Guy是的,你可以这样做。见我之前的评论。在这里,只有key
a
的值发生了变化,但另一个值保持不变。你说得对,我的错,注意你的代码可以简化!这个很好用。但是如果test_dict包含更多的键,比如
test_dict=dict({'a':1,'b':'c')
,而我不想更改'b'?那么您可以在循环中使用
test_dict={'a':i,'b':'c'}
b
的值始终是
c
。我所讨论的只是示例代码。在原始版本中,我的
test_dict
可能包含多个键,我需要更新其中的任何一个键。恐怕我不能在我的用例中使用你的建议。@Guy是的,你可以这样做。见我之前的评论。在这里,只有键
a
的值改变,但另一个保持不变。