Чтобы найти ключ в dict, вы сначала находите кандидатов по хешу, затем вы видите, является ли это случайностью (объекты разные, хотя хеш одинаков) или действительно ключ, который вы хотите. Так что, если вы не можете найти ничего под этим хешем, нечего эквалайзировать.
Представьте, что вы ищете знакомого на вечеринке и не знаете, здесь ли она. У нее рыжие волосы. Как правило, вы ищете рыжеволосых девушек, а затем идете к ним лицом к лицу, чтобы увидеть, действительно ли это она или нет. Нет смысла проверять всех и каждого на вечеринке, не пришли ли еще рыжеволосые девушки. (Предполагая, что ваш друг не увлекается ежедневной работой с красителями.)
РЕДАКТИРОВАТЬ: CPython сохраняет дикты в массиве, где позиция первичного массива определяется хешем; если эта позиция занята, она переходит к следующей позиции кандидата математически детерминированным способом. Поскольку заполненное местоположение может, следовательно, содержать либо «правильный» хеш, либо несвязанный хеш, при поиске хеша CPython начнёт с основного места, затем продолжайте сравнивать хэши, пока не решите, что искомый ключ не найден. На данный момент хэши представляют собой простые низкоуровневые целые числа, а не объекты Python, что объясняет, почему сравнения хешей не вызывают __eq__
.
Обратите внимание на симпатичную оптимизацию в источнике: для каждого кандидата CPython сначала проверяет идентичность объекта; только тогда он проверяет, все ли одинаковые хэши, и, если это так, переходит к медленной проверке, чтобы увидеть, равны ли объекты (используя PyObject_RichCompareBool
, что в итоге вызывает __eq__
). Почему это важно? Смотрите здесь:
class Foo:
def __eq__(self, other):
return False # This shouldn't match...
def __hash__(self):
return 7
f = Foo()
d = { f: "Yes!" }
print(d[f]) # ...and yet it does! :)
# => "Yes!"