具有奇怪填充行为的python嵌套字典
我在Python2.7.12嵌套dict中看到了一个奇怪的行为,我不明白为什么会发生这种情况。假设我有这本字典:具有奇怪填充行为的python嵌套字典,python,dictionary,Python,Dictionary,我在Python2.7.12嵌套dict中看到了一个奇怪的行为,我不明白为什么会发生这种情况。假设我有这本字典: list_1 = ['5', '10', '15', '30'] dict_1 = { i:[] for i in list_1 } 现在我创建一个嵌套的dict,如下所示: list_2 = ['a', 'b'] dict_2 = { i:dict_1 for i in list_2 } 还有一个嵌套的dict,如下所示: dict_3 = { i:{j:[] for j in
list_1 = ['5', '10', '15', '30']
dict_1 = { i:[] for i in list_1 }
现在我创建一个嵌套的dict,如下所示:
list_2 = ['a', 'b']
dict_2 = { i:dict_1 for i in list_2 }
还有一个嵌套的dict,如下所示:
dict_3 = { i:{j:[] for j in list_1} for i in list_2 }
如果在我填写前打印,则dict_3和dict_2是相同的:
{'a': {'15': [], '10': [], '30': [], '5': []}, 'b': {'15': [], '10': [], '30': [], '5': []}}
但是当我把字典填好的时候,比如:
dict_2['a']['5'].append(1)
dict_3['a']['5'].append(1)
dict_2有一个我不想要的行为,在“a”和“b”中填充元素“5”:
{'a': {'15': [], '10': [], '30': [], '5': [1]}, 'b': {'15': [], '10': [], '30': [], '5': [1]}}
dict_1具有我想要的行为,只在“a”中填充元素“5”:
{'a': {'15': [], '10': [], '30': [], '5': [1]}, 'b': {'15': [], '10': [], '30': [], '5': []}}
我猜想在dict\u2中嵌套dict_u1只是到该字典的链接,而dict_3是一个真正嵌套的字典。对吗?无论如何,我发现python dicts的这种用法很容易引起误解,如果它不是bug,为什么python中需要这种行为?赋值从不复制数据。只是在理解中看作业有点难
dict_2 = {i:dict_1 for i in list_2}
相当于
dict_2 = {}
for i in list_2:
dict_2[i] = dict_1 # the assignments I'm talking about
现在您有了dict_2[i]
作为所有i
的dict_1
参考。不复制任何数据。内存中有一个值为{'15':[],'10':[],'30':[],'5':[]}
的字典,它的名字正好是dict_1
,但现在也被dict_2
中的所有键引用。(内存中可以有多个相同值的名称/引用。)
如果你想要字典的真实深度副本,使用
>>> from copy import deepcopy
>>> dict_2 = {i:deepcopy(dict_1) for i in list_2}
>>> dict_2['a']['5'].append(1)
>>> dict_2
{'a': {'10': [], '30': [], '15': [], '5': [1]}, 'b': {'10': [], '30': [], '15': [], '5': []}}
同样的逻辑也适用于dict_3为什么你认为这很奇怪
dict_2
包含对同一dict_1
的两个引用,而{}
comprehension每次被调用时都会创建一个新的字典。@dhke对于那些来自可以复制数据的语言的人来说,这很奇怪。@timgeb Point接受了。@dhke觉得很奇怪,因为我是调试时最后一个想到的人。@timgeb所说的是正确的,但由于Python涵盖了指针,我花了一段时间才明白我在做一个引用,而不是创建一个新的dict。现在这更清楚了,我已经对列表和dict做了更多的测试,是的,我不明白赋值实际上是引用。无论如何,这仍然有点误导,因为:a=0
<代码>b=a<代码>a=10<代码>打印一份<代码>打印b;在这种情况下,输出将是10和0,这意味着有赋值时会有一个副本!我希望代码是可读的。@ianmartipostoma不,在Python中,赋值从不复制数据。这是真的。总是。在您的示例中就是这样:您将名称a
绑定到值0
。然后将另一个名称,b
绑定到内存中的同一个对象。然后将名称a
重新绑定到另一个值。此操作不影响名称b
指向的内容。在这个过程中没有复制任何数据。因此,在我的上一个示例中,我做了与列表中I的dict_2['b']={I:[]相同的操作,通过这种方式,我将dict_2['b']
元素重新绑定到另一个值,而无需重新绑定dict_2['a']
元素。好啊非常感谢,我会记住的!