python字典中的键

Mar*_*ark 0 python hash dictionary

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

我有一个类Path为我实现__hash____eq__

我有一个类型Path为 a的项目,dict证明如下

path in list(thedict)
>> True
Run Code Online (Sandbox Code Playgroud)

我确认path == other,并hash(path) == hash(other)id(path) == id(other)那里other取直出的项目list(thedict.keys())。然而,我得到以下

path in thedict:
>> False
Run Code Online (Sandbox Code Playgroud)

并尝试以下结果 KeyError

thedict[path]
Run Code Online (Sandbox Code Playgroud)

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

更多信息

如果有帮助,下面列出了有问题的类。正是在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
Run Code Online (Sandbox Code Playgroud)

为了回应下面的评论,这里是 (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
Run Code Online (Sandbox Code Playgroud)

Sha*_*ger 6

根据您的评论

该路径确实希望是可变的,因为我设置specificationNameNone的地方(让他们匿名稍后填写)。此外,在这样的情况:在specificationNameNone出现这种情况,但是在我的简单测试脚本我可以逃脱没有一个错误此设置为无。可散列实例的可变性是否会导致这样的错误?

那是你的问题。您dict在创建后立即将这些对象放入 a 中,而specificationNameis None,因此它dict使用基于的哈希码存储在中None(该哈希码缓存在dict自身中,并且使用该哈希码是将来查找对象的唯一方法)。如果随后将其更改为任何东西产生不同的散列值(读取几乎所有其他),对象存储在对应于旧的散列码一斗,但用它来查找计算新的散列码并不能找到桶。

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

  • 另外,避免实现您自己的“__hash__”和“__eq__”。让“dataclass”为您做这件事。原来还有这么多陷阱啊…… (3认同)
  • 如果有人想要它,这里是一个最小的实际例子:https://gist.github.com/Multihuntr/7756efa077b7837e494098adf0053dac (2认同)