Подтвердить что ты не робот

Ввод двух ключей с одним и тем же хэшем в dict

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

Почему dict разрешает использовать несколько слотов, если эти хэши ключей одинаковы?

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

И каким образом индексирование позволяет решить правильное значение для комплексного литерального индексирования? Почему эти цифры не сравниваются равными, когда они равны int(1)?

Python 2.7.12.

4b9b3361

Ответ 1

Как принятый ответ , упомянутый состояниями @CoryKramer, равенство хешей не означает равенства объектов. Словари Python могут содержать любое количество элементов с равными хэшами, если сами объекты не равны.

Короткий ответ на ваш вопрос, вероятно, в том, что реализация типа complex немного неполна в библиотеке Python с версии 2.7. Как указывает @wim, сравнение int и complex с использованием == отлично работает, но сравнение Decimal и complex не выполняется. Поскольку сравнение 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.

Ответ 2

Проблема заключается только при использовании десятичного числа с комплексным числом. Float's, int и т.д. Работают нормально, поскольку их принуждают к сравнению.

В 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 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

Почему len(set([1, Decimal('1'), (1+0j)])) == 2 - это потому, что Decimal сравнивается с int первым, если вы меняете порядок, вы получаете другой результат:

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}

Кроме того, использование литерала лучше, так как порядок, который вы вставляете, соответствует документам, так как в последнем значении сохраняется, используя литерал над набором (..).

Ответ 3

Почему дикт разрешает использовать несколько слотов, когда эти ключи хеш то же самое?

TL;DR; Поскольку встречаются хэш-столкновения

Если два хэша ключей имеют одно и то же значение, единственный способ определить, являются ли эти ключи равными, - сравнить их. Если сравнение оценивается как false, тогда dict создает несколько слотов для значений ключа в противном случае, значение для ключа перезаписывается новым значением

И каким образом индексирование позволяет решить правильное значение для комплексного литерального индексирования? Почему эти цифры не сравниваются одинаково, когда они равны int (1)?

Python использует утиную печать для определения типа значения. Имея это в виду, поскольку сами значения не содержат явного указания того, какой тип они являются, я считаю, что dict внутренне проверяет типы объектов, прежде чем пытаться их сравнить. Система печати утиных Python позволяет сделать вывод, что первая является Decimal, а вторая - типом complex. Предполагая, что это учитывается до того, как значения будут сравнены, тогда они всегда будут приводить к хешированию в разные ведра, даже если они "равны"

Причиной этого является то, что метод __eq__ для обоих классов не оценивает значение true, когда они оба сравниваются внутри объекта dict