Python 为什么字典键必须是不可变的?

Python 为什么字典键必须是不可变的?,python,dictionary,key,immutability,Python,Dictionary,Key,Immutability,为什么字典键必须是不可变的?我正在寻找一个简单、明确的原因来解释为什么Python字典中的键具有这种限制 作为Fredrik Lundh: 字典的哈希表实现使用哈希值 从键值计算以查找键。如果钥匙是一把钥匙 可变对象,其值可以更改,因此其哈希也可以更改 改变但是,无论是谁更改了关键对象,都无法识别它 被用作字典键,无法在中移动条目 字典。然后,当您尝试在 无法找到它,因为它的哈希值不同。如果 你试图查找旧值,但也找不到, 因为在该散列箱中找到的对象的值 不一样 在我的电脑上,有一个文件/etc/

为什么字典键必须是不可变的?我正在寻找一个简单、明确的原因来解释为什么Python字典中的键具有这种限制

作为Fredrik Lundh:

字典的哈希表实现使用哈希值 从键值计算以查找键。如果钥匙是一把钥匙 可变对象,其值可以更改,因此其哈希也可以更改 改变但是,无论是谁更改了关键对象,都无法识别它 被用作字典键,无法在中移动条目 字典。然后,当您尝试在 无法找到它,因为它的哈希值不同。如果 你试图查找旧值,但也找不到, 因为在该散列箱中找到的对象的值 不一样


在我的电脑上,有一个文件
/etc/dictionares common/words
,包含大量英语单词:

>>> with open("/etc/dictionaries-common/words") as f:
...     words = [line.strip() for line in f]
... 
>>> "python" in words
True
>>> "BDFL" in words
False
让我们创建一个字典来存储所有这些单词的长度:

>>> word_lengths = {w: len(w) for w in words}
>>> word_lengths["parrot"]
6
而且,为了好玩,我们将洗牌我们原来的单词列表:

>>> from random import shuffle
>>> shuffle(words)
>>> words[:5]
["Willie's", 'Araceli', 'accessed', 'engagingly', 'hobnobs']
嗯。无论如何现在我们已经把
单词弄得乱七八糟了
,我们变得有点偏执了(可能是因为同样的原因,我们渴望hobnobs),我们想检查我们的
单词长度
字典中的所有单词在我们把它们混在一起后是否仍然在
单词中:

>>> all(w in words for w in word_lengths)
True
好吧,我们到了那里,但在我的机器上花了三分钟——至少有足够的时间多吃几块美味的饼干。想一想,很明显原因是:我们有

>>> len(words)
99171
。。。要检查将近十万个单词,对于字典中的每一个单词,Python都必须在我们混乱的单词列表中进行搜索,直到找到匹配的单词。它不必总是检查整个列表,但平均每次检查五万个单词(或列表的一半),总共进行50000×100000=5000000000次测试。即使在这个奇迹般的科技时代,50亿美元也是一大笔钱

为了绝对确定(我通常不那么偏执;通常我只是困了),让我们从另一个角度检查一下,并确保
单词中的所有内容仍然在
单词长度中:

>>> all(w in word_lengths for w in words)
True
嘿,什么?这次大概是十分之一秒!有什么好处?你把我吓坏了,伙计。。。嘿,我的饼干呢?我刚才有,我肯定

与列表不同,它可以按任何旧的顺序排列(因此确保某些项目在列表中意味着依次检查每个项目,直到找到它为止),字典的效率要高一些。派对上可能没那么好玩,但嘿,让它负责音乐,一切都会好起来的,你知道吗

字典无情效率的秘密在于,对于每个项,字典根据其内容计算密钥的散列(实际上只是一个整数),并使用该散列将项存储在内存中的特定位置。然后,当您查找项目时,它会再次计算密钥内容的散列,对自己说“好的,
“python”
,散列到
7036520087640895475
…是的,我知道我一定把它放在哪里了”,然后直接到正确的内存位置找到它。所以这一次,它只需要做十万张支票,而不是五十亿张

这有点像把你所有的CD整齐地按字母顺序放在架子上,而不是随机地从盒子里放在你的扬声器上。我告诉你,字典知道它在哪里

但是,词典能够把它们放在一起是有代价的。还记得我说过字典根据项目的内容计算哈希吗?那么,如果内容发生变化会发生什么?对于不可变的对象来说,这不是问题——它们的内容不能改变——但根据定义,可变对象可以改变它们的内容,当它们改变时,它们的散列(如果它们有散列)也会改变。这很酷,很明显,不是每个人都想被放进盒子里,我明白了,但是如果散列已经改变了,字典就无法确定它把东西放在哪里了

就好像Joy Division把他们的名字改成了New Order,现在你不知道你把12英寸的蓝色星期一混音放在哪里了。这根本不起作用


因此,字典有一条规则:如果你想成为一个键,不要去改变

如果键可以改变,如何确保它能找到正确的键?我建议你关注一下你是否对实现感兴趣。这个问题是关于Python编程语言中的设计决策,而不是关于如何解决sp特殊问题。它也在Python在线文档中被回答:Python 3。x:你在溢出博客中被提到了,你应得的:你会为快乐划分/新秩序类推而投票,但是看了你的个人资料,我现在就要投票了,因为你是我第一个。甚至在这里谁是本地人。