python字典长度可变吗_python – 为什么字典键必须是不可变的?

在我的计算机上,有一个文件/ etc / dictionaries-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.无论如何……现在我们已经用言语搞砸了一下,我们变得有点偏执(可能与我们渴望hobnobs的原因相同),我们想要检查所有的我们将word_lengths词典中的单词混合起来之后仍然是单词:

>>> all(w in words for w in word_lengths)

True

好吧,我们到了那里,但在我的机器上花了三分多钟 – 至少有足够的时间吃几块美味的饼干.考虑到这一点,很明显为什么:我们有……

>>> len(words)

99171

…要检查的近十万个单词,对于字典中的每个单词,Python必须搜索我们混合的单词列表,直到找到匹配项.它并不总是必须检查整个列表,但平均每次将是五万字(或列表的一半),总共50,000×100,000 = 5,000,000,000次测试.即使在这个奇迹般的技术时代,也有五十亿.

只是为了绝对肯定(我通常不是那么偏执;通常我只是困了),让我们检查相反的方式,并确保单词中的所有内容仍然是word_lengths:

>>> all(w in word_lengths for w in words)

True

嘿,什么?这次是十分之一秒!是什么赋予了?你吓坏我了,伙计……嘿,我的饼干在哪里?我刚才有他们,我很确定.

与列表不同,列表可以是任何旧的顺序(因此确保某些项目在那里意味着依次检查每个项目,直到我们找到它),字典更有效.在聚会上可能不那么有趣,但嘿,让它掌控音乐,所有都是copacetic,你知道吗?

字典无情效率的秘诀在于,对于每个项目,字典根据其内容计算密钥的哈希(实际上只是一个整数),并使用它来将项目存储在内存中的特定位置.然后,当你去寻找项目时,它会再次计算密钥内容的哈希值,对自己说“好吧”,“python”,哈希到7036520087640895475 ……是的,我知道我必须把它放在哪里,然后“ ,并直接到正确的内存位置找到它.所以这一次,它只需要进行十万次检查,而不是五十亿次.

这有点像把所有的CD整齐地放在架子上,而不是随机堆叠在扬声器顶部.我告诉你,字典知道它在哪里.

但是要为字典保持整合的能力付出代价.还记得当我说字典根据项目的内容计算哈希值时吗?那么,如果内容发生变化会怎样?对于不存在问题的不可变对象 – 它们的内容不能改变 – 但是根据定义,可变对象可以改变它们的内容,当它们这样做时,它们的哈希(如果它们甚至有一个)也会改变.这很酷,很明显,不是每个人都想放在一个盒子里,我明白了,但是如果哈希发生了变化,那么字典就无法解决它所放置的问题.

这就像Joy Division将他们的名字改为New Order一样,现在你不知道你把蓝色星期一的12“混音放在哪里.它只是不会起作用.

所以,词典有一条规则:如果你想成为一把钥匙,就不要改变.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值