将两个哈希值相同的键放入字典中

12
>>> one_decimal = Decimal('1')
>>> one_complex = complex(1,0)
>>> d = {one_decimal: '1D', one_complex: '1C'}
>>> len(d)
2
>>> map(hash, d)
[1, 1]

上面我创建了一个具有哈希冲突和两个已占用槽位的字典。

>>> d[1]
'1D'
>>> d[1+0j]
'1C'

在整数 1 上如何处理getitem?索引如何解析复合文本索引的正确值?

Python 2.7.12 / Linux。


4
Python可以处理哈希冲突。更多信息请查看此链接 - Cory Kramer
比哈希碰撞更让我困扰的是 one_decimal == one_complex 的结果为 True - Mad Physicist
1
有趣的是,正是因为这个原因,它在Py3中不能正常工作。 - Mad Physicist
4
更好的玩法:len(set([Decimal('1'), (1+0j)]))为2,但是len(set([1, Decimal('1'), (1+0j)]))却为1。 - wim
1
我认为你应该看一下:Laurent Luce关于Python字典实现的博客 - Moinuddin Quadri
显示剩余7条评论
2个回答

6
正如@CoryKramer提出的被接受的答案所述,哈希的相等并不意味着对象的相等。Python字典可以包含任意数量的具有相等哈希的元素,只要对象本身不相等。
简短回答你的问题可能是,在Python库2.7版本中,complex类型的实现有点不完整。正如@wim指出的那样,使用==比较int和complex类型是可以的,但比较Decimal和complex类型是不可以的。由于因为它们的类型而总是返回False,所以one_decimal == one_complex将永远返回False,它们都可以存在于Python 2.7中的同一个字典中。
这个问题在Python 3中已经得到了解决。我正在尝试使用3.5,在那里one_decimal和one_complex是相等的。运行相同代码片段后,字典包含预期的值,即将one_complex的值存储在one_decimal的键下(第一个键,最后一个值)。
TL;DR:Py2.7中的complex类型有一个错误,在Py3中已经修复。

3
问题仅当使用复数时与十进制数一起使用。浮点数、整数等按强制转换进行比较,工作正常。
Python3 的十进制库中,与复数比较是在 _convert_for_comparison 中处理的。
    # Comparisons with float and complex types.  == and != comparisons
    # with complex numbers should succeed, returning either True or False
    # as appropriate.  Other comparisons return NotImplemented.
    if equality_op and isinstance(other, _numbers.Complex) and other.imag == 0:
        other = other.real

在Python2中,convert 函数的实现方式是:
def _convert_other(other, raiseit=False, allow_float=False):
    """Convert other to Decimal.

    Verifies that it's ok to use in an implicit construction.
    If allow_float is true, allow conversion from float;  this
    is used in the comparison methods (__eq__ and friends).

    """
    if isinstance(other, Decimal):
        return other
    if isinstance(other, (int, long)):
        return Decimal(other)
    if allow_float and isinstance(other, float):
        return Decimal.from_float(other)

    if raiseit:
        raise TypeError("Unable to convert %s to Decimal" % other)
    return NotImplemented

由于首先将Decimal与int进行比较,因此len(set([1, Decimal('1'), (1+0j)])) == 2为真。如果更改顺序,则会得到不同的输出结果。
In [23]: {1, Decimal('1'), (1+0j)}
Out[23]: {(1+0j), Decimal('1')}

In [24]: {Decimal('1'),1, (1+0j)}
Out[24]: {(1+0j), Decimal('1')}

In [25]: {Decimal('1'), (1+0j), 1}
Out[25]: {1}

同时使用字面量更好,因为你插入的顺序与文档匹配,就像最后一个值是preserved一样,使用字面量而不是set(..)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接