You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python字典存在对应Key却报KeyError?NetworkX AtlasView调试疑难

解析NetworkX AtlasView中诡异的KeyError问题

哇,这个问题真的太反直觉了——明明是同一个对象(id相同、is和==都返回True),却在字典里找不到,转成集合又能匹配上,简直让人摸不着头脑!先把你遇到的诡异现象再清晰列出来,方便大家理解:

>>> type(self._atlas)
<class 'dict'>
>>> type(key)
<class 'SyntaxToken'>
>>> self._atlas[key]
Traceback (most recent call last):
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2019.3.1\plugins\python-ce\helpers\pydev\_pydevd_bundle\pydevd_exec2.py", line 3, in Exec
    exec(exp, global_vars, local_vars)
File "<input>", line 1, in <module>
KeyError: при
>>> list(self._atlas.keys())[0] is key
True
>>> list(self._atlas.keys())[0] == key
True
>>> key in self._atlas
False
>>> key in set(self._atlas.keys())
True
>>> id(key), id(list(self._atlas.keys())[0])
(2487509812032, 2487509812032)

问题根源分析

出现这种矛盾现象的核心原因是字典的哈希表机制和SyntaxToken类的哈希实现不兼容,具体来说:

  1. Python字典的in操作和__getitem__是先通过对象的哈希值定位到对应的桶,再在桶内比较对象是否相等;
  2. 从id相同可以确定这是同一个对象,但key in self._atlas返回False,说明当前对象的哈希值和它被存入字典时的哈希值不一样了;
  3. 为什么转成集合就可以找到?因为set(self._atlas.keys())会把字典里的键重新加入集合,这时候用的是对象当前的哈希值,而集合的in操作是基于当前哈希值来判断的,所以能匹配上。

导致哈希值变化的大概率原因是:

  • SyntaxToken类重写了__hash__方法,但该方法依赖了可变的实例属性;
  • 这个key对象被存入字典后,它的某个可变属性被修改了,导致哈希值发生了变化;
  • 字典无法感知到哈希值的变化,仍然按照存入时的哈希值去查找,自然找不到对应的条目。

另外还有一种可能:如果SyntaxToken重写了__eq__但没有重写__hash__,不过这种情况通常在存入字典时就会抛出TypeError(因为默认__hash__会被设为None),所以你的情况更倾向于前者。

解决方案

针对这个问题,你可以按以下步骤修复:

  • 检查SyntaxToken的哈希实现:
    确保__hash__方法只依赖对象的不可变属性(比如字符串、数字这类不可变类型),同时遵循Python规范:如果两个对象==相等,它们的__hash__必须返回相同的值。

  • 避免修改字典键的可变属性:
    如果你必须使用SyntaxToken作为字典键,那么在将其存入字典后,绝对不要修改它的任何会影响哈希值的属性;最好把SyntaxToken设计成不可变类(比如用dataclasses.dataclass(frozen=True)来定义,或者手动限制属性修改)。

  • 临时应急方案:
    如果暂时没法修改SyntaxToken的实现,可以通过遍历字典键的方式查找对应的条目(虽然效率低,但能解决当前问题):

    # 替代self._atlas[key]的查找方式
    for k, v in self._atlas.items():
        if k == key:
            value = v
            break
    else:
        raise KeyError(key)
    

内容的提问来源于stack exchange,提问作者nivedano

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 09:07:41