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

Python, контрольная сумма dict

Я собираюсь создать контрольную сумму dict, чтобы узнать, была ли она изменена или нет На данный момент у меня это:

>>> import hashlib
>>> import pickle
>>> d = {'k': 'v', 'k2': 'v2'}
>>> z = pickle.dumps(d)
>>> hashlib.md5(z).hexdigest()
'8521955ed8c63c554744058c9888dc30'

Возможно, лучшее решение существует?

Примечание. Я хочу создать уникальный идентификатор dict для создания хорошего Etag.

EDIT: Я могу иметь абстрактные данные в dict.

4b9b3361

Ответ 1

Что-то вроде этого:

reduce(lambda x,y : x^y, [hash(item) for item in d.items()])

Возьмите хэш каждого (ключа, значения) кортежа в dict и XOR их alltogether.

@katrielalex Если dict содержит не подлежащие удалению элементы, вы можете сделать это:

hash(str(d))

или, может быть, даже лучше

hash(repr(d))

Ответ 2

Я не знаю, гарантирует ли pickle, что хэш сериализуется одинаково каждый раз.

Если у вас есть только словари, я бы выбрал комбинацию вызовов keys(), sorted(), построил строку на основе отсортированных пар ключ/значение и вычислил контрольную сумму для этого

Ответ 3

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

Ответ 4

Я думаю, вы не можете понять некоторые тонкости, которые идут на это. Первая проблема заключается в том, что порядок, в котором элементы отображаются в dict, не определяется реализацией. Это означает, что просто запрос str dict не работает, потому что вы могли бы иметь

str(d1) == "{'a':1, 'b':2}"
str(d2) == "{'b':2, 'a':1}"

и они будут иметь хеш для разных значений. Если у вас есть только хешируемые элементы в dict, вы можете их хешировать, а затем объединить свои хэши, поскольку @Bart делает или просто

hash(tuple(sorted(hash(x) for x in d.items())))

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

НО было бы легко сломать любую реализацию, как это, если вы разрешаете произвольные данные в словаре, так как вы можете просто написать объект со сломанной реализацией __hash__ и использовать его. И вы не можете использовать id, потому что тогда у вас могут быть равные элементы, которые сравнивают разные.

Мораль истории состоит в том, что хэширование dicts не поддерживается в Python по какой-то причине.

Ответ 5

В Python 3 хэш-функция инициализируется случайным числом, которое отличается для каждого сеанса python. Если это неприемлемо для предполагаемого приложения, используйте, например, zlib.adler32 для создания контрольной суммы для dict:

import zlib

d={'key1':'value1','key2':'value2'}
checksum=0
for item in d.items():
    c1 = 1
    for t in item:
        c1 = zlib.adler32(bytes(repr(t),'utf-8'), c1)
    checksum=checksum ^ c1

print(checksum)