Python, контрольная сумма диктанта - PullRequest
12 голосов
/ 03 августа 2011

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

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

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

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

РЕДАКТИРОВАТЬ: Я могу иметь абстрактные данные в диктовке.

Ответы [ 5 ]

9 голосов
/ 03 августа 2011

Примерно так:

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

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

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

hash(str(d))

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

hash(repr(d))
1 голос
/ 10 февраля 2017

В 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)
1 голос
/ 03 августа 2011

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

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

0 голосов
/ 03 августа 2011

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

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

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

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

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

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

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

0 голосов
/ 03 августа 2011

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

...