Как вычисляется хэш (нет)?

#python #hash

#питон #хэш #python

Вопрос:

На моей машине hash(None) возвращает значение:

 >>> hash(None)
-2138947203
  

Просто из любопытства, как вычисляется это хэш-значение? Не похоже, что это значение основано на None ‘s id , поскольку оно будет таким же, если я перезапущу интерпретатор Python.

Комментарии:

1. Не совпадает ли идентификатор (нет) при перезапуске интерпретатора Python?

2. на самом деле оба id и hash равны при перезапуске Python. Я бы предположил, что это просто какая-то позиция внутри двоичного файла Python.

3. Интересные моменты. Я даже не подумал это проверить!

Ответ №1:

Он основан на None id , но None является одним из нескольких объектов Python, которые определены как глобальные переменные C, поэтому его адрес (обычно) не меняется между запусками Python. Другими такими объектами являются True and False (но они хэшируются как целые числа) или встроенные классы, такие как object and tuple .

Однако адрес (и хэш) различаются в разных сборках CPython. В моей системе hash(None) выдает 539708.

Комментарии:

1. Излишне говорить, что это деталь реализации CPython, поэтому вам не следует полагаться на нее.

2. Просто из любопытства, как можно на это полагаться?

3. @ChrisW., нет, это не будет проблемой, поскольку hash() этого объекта все равно останется неизменным до тех пор, пока объект живет (поскольку вы не можете перемещать живые объекты в разные сеансы Python).

4. @ChrisW. ДА. Это также произойдет, например True , с любым объектом, который не переопределяется __hash__ . И с PYTHONHASHSEED установленным значением random (рекомендуется для веб-серверов) для строк.

5. Обратите внимание, что адрес может меняться между запусками одного и того же двоичного файла pythong, если в вашей операционной системе включена рандомизация адресного пространства.

Ответ №2:

Он основан на адресе None в памяти, как указано в определении типа.

Комментарии:

1. ссылка мертва, вы должны были включить соответствующую часть содержимого ссылки в свой ответ

Ответ №3:

Как None и объект, я написал функцию object_hash для вычисления хэша объекта:

 import sys
import struct

def int_overflow(value):
    """ simulate integer overflow """
    m = sys.maxint   1
    return (value   m) % (m * 2) - m

def object_hash(value):
    res = id(value)
    sizeof_void_p = struct.calcsize('P')
    res = int_overflow((res >> 4) | (res << (8 * sizeof_void_p - 4)))
    if res == -1:
        res = -2
    return res
  

Результирующие хэши равны:

 >>> hash(None)
492116
>>> object_hash(None)
492116L
  

Ответ №4:

Начиная с Python v3.12.0a4 и CPython PR #99541, значение хэша None теперь является постоянным.