为什么我的字典在可变和不可变之间交替?

Why are my dicts alternating between mutable and immutable?

提问人:MrPoulet 提问时间:2/17/2020 最后编辑:MrPoulet 更新时间:2/17/2020 访问量:60

问:

请考虑以下代码

from pprint import pprint
test_dict = {}
new = {}
new['slot'] = {}
for k in range(5):
    test_dict[k] = {}
    test_dict[k].update(new)
    if k == 3:
        test_dict[k]['slot']['this should only be in 3'] = []
pprint(test_dict)
print('Round 2, without SLOT')
test_dict = {}
new = {}
for k in range(5):
    test_dict[k] = {}
    test_dict[k].update(new)
    if k == 3:
        test_dict[k]['this should only be in 3'] = []
pprint(test_dict)

使用此输出

> python -i .\test2.py
{0: {'slot': {'this should only be in 3': []}},
 1: {'slot': {'this should only be in 3': []}},
 2: {'slot': {'this should only be in 3': []}},
 3: {'slot': {'this should only be in 3': []}},
 4: {'slot': {'this should only be in 3': []}}}
Round 2, without SLOT
{0: {}, 1: {}, 2: {}, 3: {'this should only be in 3': []}, 4: {}}

帮助我理解为什么在第一种情况下,“应该只是......”列表出现在每种情况下,而不是第二种情况下。字典是不可变的,但我不明白为什么我会得到不同的结果。

谢谢

python-3.x 不变性 可变

评论

4赞 khelwood 2/17/2020
设置为空字典。然后,在多个其他容器中引用该字典(通过 )。然后你改变它。字典不是一成不变的。new['slot'].update(new)
1赞 a_guest 2/17/2020
“字典是不可变的,但我不明白为什么我会得到不同的结果。”这是一个虚假的说法。字典是非常可变的。new['slot']
0赞 MrPoulet 2/19/2020
好吧,我不明白的最后一件事是为什么它在第二次测试中没有发生。我在这两种情况下都复制了字典,唯一的区别是在测试 1 中,“插槽”字典被添加到“new”中。
0赞 MrPoulet 2/19/2020
让我进一步阐述这一点。如果我为测试 1 中的所有内容打印 (id),则 test_dict[k] 每次迭代都有一个唯一的 ID,但 test_dict[k]['slot'] 每次都是相同的。我不明白这种现象。对我来说,它们要么完全相同,要么都是独一无二的。

答:

0赞 chepner 2/17/2020 #1

该方法不会为 中的每个条目创建副本。updatenew['slot']test_dict

test_dict = {}
new = {}
new['slot'] = {}
for k in range(5):
    test_dict[k] = {}
    test_dict[k].update(new)
    if k == 3:
        test_dict[k]['slot']['this should only be in 3'] = []

test_dict[k]['slot']是对每个 . 的相同引用。您可以通过以下方式确认这一点:dictk = 0, 1, ..., 4id

>>> for k in range(5): id(test_dict[k]['slot'])
...
4422633104
4422633104
4422633104
4422633104
4422633104
>>> id(new['slot'])
4422633104

评论

0赞 MrPoulet 2/17/2020
所以你是说如果我做update(new),我正在创建一个新的“新”字典。但是如果我写 update(new['slot']),我每次都会插入相同的 'slot' 副本。
0赞 chepner 2/17/2020
不,本质上只是一个包装器。唯一可能创建的新内容是 中的新键。test_dict[k].update(new)for i in new: test_dict[k][i] = new[i]test_dict[k]
1赞 user3657941 2/17/2020 #2

您将存储在以下每个键中的相同实例:dictnew['slot']test_dict

from pprint import pprint
test_dict = {}
new = {}
new['slot'] = {}
new['slot']['id'] = id(new['slot'])
for k in range(5):
    test_dict[k] = {}
    test_dict[k].update(new)
    if k == 3:
        test_dict[k]['slot']['this should only be in 3'] = []
pprint(test_dict)

输出

{0: {'slot': {'id': 4433735760, 'this should only be in 3': []}},
 1: {'slot': {'id': 4433735760, 'this should only be in 3': []}},
 2: {'slot': {'id': 4433735760, 'this should only be in 3': []}},
 3: {'slot': {'id': 4433735760, 'this should only be in 3': []}},
 4: {'slot': {'id': 4433735760, 'this should only be in 3': []}}}

一个可能的解决方法是在每次需要时创建一个新的:dict

from pprint import pprint
test_dict = {}
for k in range(5):
    test_dict[k] = {}
    new = {'slot': dict()}
    new['slot']['id'] = id(new['slot'])
    test_dict[k].update(new)
    if k == 3:
        test_dict[k]['slot']['this should only be in 3'] = []
pprint(test_dict)

输出

{0: {'slot': {'id': 4399711968}},
 1: {'slot': {'id': 4399712528}},
 2: {'slot': {'id': 4399713088}},
 3: {'slot': {'id': 4399713648, 'this should only be in 3': []}},
 4: {'slot': {'id': 4399730768}}}