2011-08-03 15 views
11

myślę stworzyć kontrolną dict wiedzieć, czy została zmodyfikowana lub nie Na razie muszę, że:Python, suma kontrolna dict

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

Być może lepszym rozwiązaniem istnieje?

Uwaga: Chcę utworzyć unikalny identyfikator dyktatury, aby utworzyć prawidłowy Etag.

EDYCJA: Mogę mieć abstrakcyjne dane w dyktecie.

+0

Co zawiera Twój dyktat? Jeśli to tylko ciągi (powiedzmy), możesz po prostu posortować posortowane ciągi znaków: 'hash (repr (posortowane (my_dict.items())))'. – katrielalex

+0

Co to są dane abstrakcyjne? Stabilność i działanie algorytmu mieszania dyktującego zależy w dużej mierze od tego, jakie dane zawiera. Na przykład, jeśli masz dyktować dyktowanie? – katrielalex

+0

ten typ danych: http://code.google.com/appengine/docs/python/datastore/typesandpropertyclasses.html – sahid

Odpowiedz

7

coś takiego:

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

Zrób hasz każdej krotki (klucza, wartości) w dykcie i zmień je w XOR.

@katrielalex Jeśli DICT zawiera unhashable przedmioty można to zrobić:

hash(str(d)) 

a może nawet lepiej

hash(repr(d)) 
+0

To jest eleganckie. –

+0

Co, jeśli dyktatura zawiera elementy, których nie można odłączyć? – katrielalex

+1

Nie można wykonać 'str (d)' bez fałszywych negatywów, ponieważ kolejność, w której elementy pojawiają się w reprezentacji napisów, jest niezdefiniowana. – katrielalex

1

Nie wiem, czy pickle gwarantuje, że hash jest serializowany w ten sam sposób za każdym razem.

Jeśli masz tylko słowniki, chciałbym pójść na o kombinacji połączeń do keys(), sorted(), zbudować ciąg w oparciu o segregowanych par kluczy/wartości i obliczyć sumę kontrolną tego

+0

'" ".join ("% s,% s "% (x, y) dla x, y w posortowane (foo.iteritems())) '(gdzie foo jest dyktando) może działać jako sygnatura, którą można mieszać. –

+0

A co jeśli mam abstrakcyjne dane w moim dyktafonie? to nie jest problem? – sahid

+0

Myślę, że wtedy musiałbyś wykonać funkcję rekursywną, która serializowała posortowane dane dla każdej podstruktury. –

0

Jak sam powiedziałeś, że chcesz wygenerować wytycznych na podstawie słownika treść, OrderedDict, która zachowuje kolejność słownika, może być lepszym kandydatem tutaj. Po prostu wykonaj iterację za pomocą klucza, par wartości i skonstruuj ciąg znaków Etag.

0

Myślę, że możesz nie zdawać sobie sprawy z niektórych subtelności, które się w to mieszczą. Pierwszy problem polega na tym, że kolejność elementów wyświetlanych w dykcie nie jest zdefiniowana przez implementację. Oznacza to, że po prostu prosząc o str z dict nie działa, ponieważ można mieć

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

i będą hash do różnych wartościach. Jeśli masz tylko hashable przedmioty w dict, można je hash, a następnie dołączyć do swoich skrótów, jak @Bart robi lub po prostu

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

Zanotuj sorted, bo trzeba zapewnić, że krotka haszowanej wychodzi w w tym samym porządku, niezależnie od tego, w jakim porządku elementy pojawiają się w dyktowaniu. Jeśli masz dyktatury w dyktacie, możesz to powtórzyć, ale będzie to skomplikowane.

ale byłoby łatwo złamać każdą realizację takiego jeśli pozwalają arbitralnych danych w słowniku, ponieważ można po prostu napisać obiektu ze złamanym __hash__ wdrażania i wykorzystania. I nie możesz użyć id, ponieważ wtedy możesz mieć równe przedmioty, które porównują różne.

Morał z tej historii jest taki, że dygresja hashing nie jest obsługiwana w Pythonie z jakiegoś powodu.

0

W języku Python 3 funkcja hash jest inicjalizowana za pomocą liczby losowej, która jest inna dla każdej sesji Pythona. Jeśli nie jest to dopuszczalne dla zamierzonej aplikacji, użyj np. Zlib.adler32 do budowania sumy kontrolnej dla dyktafonu:

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) 
Powiązane problemy