python 字典中的键

Keys in python dictionaries

我遇到的问题分布在许多源文件中,我尝试以简单的线性格式重现该问题,但都失败了。尽管如此,我遇到的问题只是简单描述了。

我有一个 class Path,我为此实现了 __hash____eq__

我在 dict 中有一个 Path 类型的项目,

证明了这一点
path in list(thedict)
>> True

我确认 path == otherhash(path) == hash(other)id(path) == id(other) 其中 other 是直接从 list(thedict.keys()) 中取出的项目。然而,我得到以下

path in thedict:
>> False

并在 KeyError

中尝试以下结果
thedict[path]

所以我的问题是,在什么情况下这是可能的?我本以为如果 pathlist(thedict) 中,那么它必须在 thedict.keys() 中,因此我们必须能够写 thedict[path]。这个假设有什么问题?

更多信息

如果有帮助,下面列出了相关的 classes。在SpecificationPath级别观察到上述问题

class Path:
    pass

@dataclass
class ConfigurationPath(Path):
    configurationName: str = None
    
    def __repr__(self) -> str:
        return self.configurationName

    def __hash__(self):
        return hash(self.configurationName)

    def __eq__(self, other):
        if not isinstance(other, ConfigurationPath):
            return False
        return self.configurationName == other.configurationName

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

@dataclass
class SpecificationPath(Path):
    configurationPath: ConfigurationPath
    specificationName: str = None
    
    def __repr__(self) -> str:
        return f"{self.configurationPath}.{self.specificationName or ''}"

    def __hash__(self):
        return hash((self.configurationPath, self.specificationName))
    
    def __eq__(self, other):
        if not isinstance(other, SpecificationPath):
            return False
        if self.configurationPath != other.configurationPath:
            return False
        if self.specificationName != other.specificationName:
            return False
        return True

为了回应下面的评论,这是 (Spyder) 调试终端中的输出,其中 pf 是一个对象,其中包含使用路径作为键的 paths 字典和相关对象(self) 有路径。

In : others = list(pf.paths.keys())
In : other = others[1]
In : self.path is other
Out[1]: True
In : self.path in pf.paths
Out[1]: False

根据 :

The paths do want to be mutable as I am setting specificationName to None in places (leaving them Anonymous to be filled out later). Further, it is on an instance where the specificationName is None that this occurs, however in my simple test scripts I can get away with setting this to None without an error. Could mutability of the hashable instances cause an error such as this?

这是你的问题。您在创建后立即将这些对象放在 dict 中,而 specificationNameNone,因此它存储在 dict 中,哈希码基于 None (该哈希码缓存在 dict 本身中,并且使用该哈希码是将来查找对象的唯一方法)。如果您随后将其更改为 anything 以产生不同的哈希值(读取几乎所有其他内容),则该对象将存储在与旧哈希码相对应的存储桶中,但将其用于查找计算新的哈希码,找不到那个桶。

如果specificationName必须是可变的,那么它就不能成为散列的一部分,就这么简单。这可能会增加碰撞,但无济于事;如果不触发这个确切的问题,可变字段不能成为散列的一部分。