为什么字典键被转换为继承的类类型?

时间:2018-01-07 08:36:10

标签: python class dictionary

我的代码看起来像这样:

class SomeClass(str):
    pass

some_dict = {'s':42}

>>> type(some_dict.keys()[0])
str
>>> s = SomeClass('s')
>>> some_dict[s] = 40
>>> some_dict # expected: Two different keys-value pairs
{'s': 40}
>>> type(some_dict.keys()[0])
str

为什么Python将对象s转换为字符串" s"在更新字典some_dict

2 个答案:

答案 0 :(得分:17)

虽然哈希值是相关的,但它不是主要因素。  在这里,平等更为重要。也就是说,对象可能具有相同的哈希值并且不相等,但是相等的对象必须具有相同的哈希值(尽管这不是严格执行的)。否则,在使用dictset时,您会遇到一些奇怪的错误。

由于您尚未在__eq__上定义SomeClass方法,因此您继承了str上的__eq__方法。 Python的内置构建是为了允许子类化,所以's' == SomeClass('s')返回true,如果对象本来是相同的,那么它们不具有不同的类型。例如。 's'是真的。因此,SomeClass('s')__eq__等同于字典的键是正确和恰当的。

要获得所需的行为,您必须重新定义__hash__ dunder方法以考虑类型。但是,当您定义自定义等号时,python会停止为您提供自动str.__hash__ dunder方法,您也必须重新定义它。但在这种情况下,我们可以重用class SomeClass(str): def __eq__(self, other): return ( type(self) is SomeClass and type(other) is SomeClass and super().__eq__(other) ) __hash__ = str.__hash__ d = {'s': 1} d[SomeClass('s')] = 2 assert len(d) == 2 print(d)

{'s': 2, 's': 1}

打印:@"C\\"":([.0-9]*),"

答案 1 :(得分:0)

这是一个非常好的问题。首先,当把(key,value)对放入dict时,它使用哈希函数来获取密钥的哈希值,并检查是否存在该哈希码。如果存在,则dict将对象与相同的哈希码进行比较。如果两个对象相等(__eq__(self, other)返回True),则会更新该值,这就是您的代码遇到此类行为的原因。

鉴于SomeClass甚至未被修改,因此's'SomeClass('s')应具有相同的哈希码,'s'.__eq__(SomeClass('s'))将返回True。

相关问题