为什么Python字典不能在此脚本中独立处理密钥?

时间:2014-05-08 15:52:50

标签: python dictionary key key-value python-2.6

我希望通过一些启示来覆盖我的挫败感 - 这里是用于演示问题的脚本的最小版本:

首先我创建一个字典:

dic  = {
    'foo':{}, 
    'bar':{}
    }

然后我们实例化一个可以迭代追加的模板字典 到dic的键:

appendic= {  
    'is':'',       #  '' is a terminal value to be replaced later
}

所以我们在这里appendicdic中的每个键添加dic['foo'] = appendic dic['bar'] = appendic

dic['foo']['is'] = 'foo'
dic['bar']['is'] = 'bar' 

现在我们用有意义的东西替换终端值''

print(dic['foo']['is'])

此时,我的直觉告诉我,如果我们打电话:

'foo'我们得到'bar'

但是,Python会将{{1}} ...返回给我没有训练的头脑,这是违反直觉的。

问题:

  • 我如何告诉Python保持dic的密钥独立?
  • 为什么这是默认行为?这有什么用例?

4 个答案:

答案 0 :(得分:9)

当您将appendic分配给两个不同的密钥时,Python不会复制。它改为指定参考。

因此,dic['please_make_me_Foo']dic['dont_make_him_Bar']都会引用同一个对象。这些不是单独的词典,它们都是同一个对象,一个appendic 引用。

如果您希望这些是单独的词典,请改为创建appendic的副本。 dict.copy()方法创建字典的浅表副本:

dic['please_make_me_Foo']= appendic.copy()
dic['dont_make_him_Bar'] = appendic.copy()

Shallow意味着创建了一个新字典,并且复制了对包含的键和值的所有引用。

如果appendic本身包含也是字典的值,则不会复制这些值。新副本和appendic都会引用相同的值。在大多数情况下,这不是问题,因为大多数原始值(字符串,整数等)是不可变的,并且在用新的值替换这些值时,您从未注意到共享引用。

答案 1 :(得分:4)

你做了一个字典:

appendic= {  
    'Python_made_me':''
}

将其添加到您的其他词典两次

dic['please_make_me_Foo']= appendic
dic['dont_make_him_Bar'] = appendic

并设置单个字典的Python_made_me两次

dic['please_make_me_Foo']['Python_made_me'] = 'Foo'
dic['dont_make_him_Bar']['Python_made_me']  = 'Bar' 

但是因为他们是相同的词典第二行会覆盖第一行

如果您需要复制它,则需要使用copy方法:

dic['please_make_me_Foo']= appendic.copy()
dic['dont_make_him_Bar'] = appendic.copy()

答案 2 :(得分:2)

dic['please_make_me_Foo']= appendic
dic['dont_make_him_Bar'] = appendic

appendic是一个对象 - 您正在为dic中的两个键分配对同一对象的引用。所以当你换一个时,你就改变了。

请改为尝试:

dic['please_make_me_Foo']= appendic.copy()
dic['dont_make_him_Bar'] = appendic.copy()

答案 3 :(得分:2)

好吧,我只想写这个作为其他答案的补充。当您操作字典时,您将引用操作到实例,这是您的错误的根本原因。使用hex(id(foo)),您将获得foo的内存地址,因此,让我们在以下示例中显示d实例的地址,以使有形

>>> hex(id(d))
'0x10bd95e60'
>>> hex(id(e[1]))
'0x10bd95e60'
>>> hex(id(f[1]))
'0x10bd95e60'

因此,如果您添加或删除e[1]中的值,您实际上更改的是与d指向的实例相同的实例,并且字典是可变的,即你可以改变其中的值。

现在您想知道为什么在处理整数时不会发生这种情况?因为事实上确实如此,只是整数不可变:

>>> i = 1
>>> hex(id(i))
'0x10ba51e90'
>>> j = i
>>> hex(id(j))
'0x10ba51e90'
>>> i = 2
>>> hex(id(i))
'0x10ba51eb0'

即。我指着记忆中的另一个地方。

通过使用类可以创建可变整数:

>>> class Integer:
...   def __init__(self, i):
...     self.i = i
... 
>>> i = Integer(2)
>>> hex(id(i))
'0x10bd9b410'
>>> j = i
>>> hex(id(j))
'0x10bd9b410'
>>> j.i = 2
>>> i.i
2
>>> hex(id(i))
'0x10bd9b410'

要创建同一字典的新实例,您需要使用字典的copy()成员:

>>> hex(id(d))
'0x10bd95e60'
>>> w = d.copy()
>>> x = d.copy()
>>> y = d.copy()
>>> hex(id(w))
'0x10bd96128'
>>> hex(id(x))
'0x10bd95f80'
>>> hex(id(y))
'0x10bd96098'