为什么 Python 中的字典会在赋值期间检查是否存在密钥?

Why do dictionaries in Python check for a key-existing during assignment?

提问人:ZenPyro 提问时间:11/12/2023 更新时间:11/12/2023 访问量:108

问:

所以我听说 Python 中的实例会在分配值之前检查键是否已经存在。这对我来说似乎很多余,我将用一个例子来解释原因。
例:
dict

if(key in dictionary):
   dictionary[key] = dictionary[key] + 1
else:
   dictionary[key] = 1

因此,您可以在此示例中看到,无需检查 的密钥是否已存在。因为赋值右侧的 () 将检索密钥(如果存在),或者如果实例中尚不存在密钥,则引发 (请注意,检查密钥是否存在于右侧与赋值无关)。无论密钥是否已存在于左侧的检查中 (),都不会对结果产生任何影响。如果没有进行检查,并且您只是计算了 的哈希值并为其分配了 .密钥以前是否存在并不重要。 另请注意:无论有没有冗余检查,都将执行冗余检查。dictionary[key] = dictionary[key] + 1dictionary[key]dictionary[key] + 1KeyErrordictdictionary[key] =keyvalueif(key in dictionary):

对于示例的第二部分。检查中是否存在键不会改变结果,无论之前的任何值(如果存在)都会被 覆盖。那么在设置之前检查的意义何在。dictionary[key] = 1dictionary[key]key1

也许在集合之前的 ASSIGNMENT 期间进行隐式检查是有原因的。如果检查是在作业的左侧或右侧的实例,则似乎执行了单独的检查。因为缺少一个不会在左手边扔一个,所以只是做了一个新的。我看不到在集合之前需要检查的示例,但如果你这样做了!我很想听听。dictkeyKeyErrorkey

Python 字典 变量赋值 顺序

评论

2赞 Charles Duffy 11/12/2023
“听到了”?在哪里听说的?你有什么证据证明这实际上是真的?
0赞 Charles Duffy 11/12/2023
我投票决定结束这个问题,因为要切中主题,Stack Overflow 问题需要与您实际面临的狭隘、具体问题有关。担心语言级别的设计决策可能不是最优的,这不是你面临的问题,除非你能以某种可测试的方式证明你的程序因此而行为不正确。
1赞 ZenPyro 11/12/2023
@CharlesDuffy 我牢记这一点,关于词典的正确创建!但无论我在哪里听到,都无关紧要。如果在分配期间设置实例之前没有“隐式”检查,你能告诉我吗?如果你知道没有,它会完美地回答我的问题!dict
1赞 Charles Duffy 11/12/2023
特别要注意 .PyDict_SetItem
1赞 Charles Duffy 11/12/2023
无论如何,正如我所读到的,有一个检查,但它是分配中一个必要的、不可或缺的部分,以确定我们是否要替换其他东西,正确地从内存中逐出我们要替换的任何内容(或至少减少其引用计数)并重用插槽,而不是在预先存在的存储位置已经存在的情况下分配一个新的插槽。因此,它可以说是作业的重要组成部分,而不是在开始作业之前完成的事情。

答:

3赞 wim 11/12/2023 #1

实际上,Python 在设置新值时会检查字典中是否已经存在键。但是,此检查发生在 C 级别,而不是像问题中所示的 Python 代码中。检查由 CPython 中_Py_dict_lookup的帮助程序函数完成。

实现必须检查密钥是否已存在,这是有充分理由的:

  • 替换密钥时,必须递减旧值的引用计数(无内存泄漏)
  • 替换密钥时,CPython 保证不会触发后备存储大小调整(用户可以在字典迭代期间修改项目)。
  • 为了区分“密钥存在”和“哈希冲突”,可能需要在新密钥和旧密钥之间进行相等检查(冲突处理)

在编写 Python 代码时,您不需要进行这种检查。使用类似的东西会更正常:

dictionary[key] = dictionary.get(key, 0) + 1

或者,如果您只是计算键,请使用 dict 子类,例如集合。相反,计数器

评论

2赞 user2357112 11/12/2023
此外,Python 需要区分“密钥存在”和“哈希冲突”。
0赞 ZenPyro 11/12/2023
@wim 这是一个不可思议的解释!非常感谢!现在完全有道理了!
0赞 wim 11/12/2023
@user2357112 这是一个很好的观点,所以它不仅仅是内存管理细节。我将补充这一点。
0赞 ZenPyro 11/12/2023
@wim 我也不知道这是否是说这个的合适地方,但如果你能帮上忙,请阻止这个话题被关闭。我喜欢拥有它,这样我就可以随时在需要时返回它,并且您提供的链接中有许多很棒的资源可供我使用(如果它违反某种准则,请删除此评论)。如果这个话题对我有帮助,那应该是一个足够好的理由来保持开放!
1赞 wim 11/12/2023
@ZenPyro 对不起,我没有那种权威。如果另外两个用户同意 Charles,它将被关闭。但是,闭包不会导致删除,它只会阻止新的答案(即您不必担心此答案消失)。