2013-04-22 23 views
5

Rasgele bir Python nesnesi için bir karma oluşturmak için pickle.dumps kullanıyorum, ancak, dict/set emirlerinin kuralsız hale getirildiğini ve bu nedenle sonucun güvenilmez olduğunu öğrendim.Rasgele Nesneler için Hash Oluştur?

SO ve elsewhere üzerinde severalrelatedquestions vardır, ama eşitlik aynı temelini (__getstate__/__dict__ sonuç) kullanan bir karma algoritma bulmak için görünmüyor olabilir. Kendi başıma yuvarlanmanın temel gereksinimlerini anlıyorum, ama açıkçası test edilen bir şeyi kullanmayı tercih ederim.

Böyle bir kitaplık var mı? Aslında istediğim, çıktıyı hasara uğratmak için deterministik olarak nesneleri (__getstate__ ve __dict__ kullanarak) seri hale getiren bir kütüphanedir.

netleştirmek için DÜZENLEME, Python en hash (veya __hash__) tarafından döndürülen değerlerden farklı bir şey arıyorum. İstediğim şey, aslında, yıkanabilir veya bulunmayan keyfi nesneler için bir sağlama toplamıdır. Bu değer nesnelerin durumuna göre değişmelidir. (__getstate__ tarafından geri döndürülen dict'e başvurmak için "state" yi kullanıyorum veya yoksa, nesne __dict__.

+3

Ne demek istediğini anlamak yararlı olabilir. – arikb

+0

Temelde memoizasyon için. Dosya isimlerinin belirlenmesini gerektiren bir dizi parametre kullanarak dosyalar üretiyorum. Ancak, problemin genel bir çözümü ile ilgileniyorum. – matthewwithanm

+0

İki "eşit" nesneyi '__dict__' yineleme sırasına göre ayırabileceğinizi unutmayın! –

cevap

1
Pickler uzatılabilir basıp fonksiyonlar gerekli türlerini standartlaştırmanız geçersiz aklıma

, yani yaptığım şey bu. İşte göründüğü gibi:

from copy import copy 
from pickle import Pickler, MARK, DICT 
from types import DictionaryType 


class CanonicalizingPickler(Pickler): 
    dispatch = copy(Pickler.dispatch) 

    def save_set(self, obj): 
     rv = obj.__reduce_ex__(0) 
     rv = (rv[0], (sorted(rv[1][0]),), rv[2]) 
     self.save_reduce(obj=obj, *rv) 

    dispatch[set] = save_set 

    def save_dict(self, obj): 
     write = self.write 
     write(MARK + DICT) 

     self.memoize(obj) 
     self._batch_setitems(sorted(obj.iteritems())) 

    dispatch[DictionaryType] = save_dict 
0

Nesnenizi bir kez hatalı olarak kabul edeceğinizi varsayacağım. karma değerlerini hesapladı (ve sakladı). Aksi halde, yaptığınız işlere çok dikkat etmelisiniz (örneğin, setler, dikmeler vb. Depolamak için bunların elverişlilik kalitesini kullanmamalıdır).

Bu, en zarif yol, ilk önce tüm üyelerinizi __dict__ ürününüzde yıkanabilir tipte saklamak olduğunu söyledi. list s yerine, tuplleri kullanın (elbette yıkanabilir nesnelerden). dict s yerine, this sorusundaki çözümlerden herhangi birini kullanabileceğiniz şekilde yazdırabilirsiniz (ben şahsen @ alex'ın kullanıyorum). Yine, bunun çalışması için hem anahtarların hem de değerlerin yıkanabilir olması gerekir.

Ardından, __hash__ yöntem kullanabilirsiniz aynı hashable-dict sizin gibi, kullandığınız:

def _hashable_state(self): 
    return MyHashableDict(self.__dict__) 
def __hash__(self): 
    return hash(self._hashable_state()) 
def __reduce__(self): 
    return self._hashable_state() 
+0

Evet, nesnelerimi değişmez olarak ele alma konusunda haklısınız. Ancak rasgele (seçilebilir) nesneler için çalışacak bir şey arıyorum. Yani, iki nesnenin, devlet sözlüğünde ('__dict__' veya' __getstate __() 'sonucu) tüm öğeleri aynı karma değere sahip olması gerekir (yinelemeli durum) veya (ilkel veya başka nesneler için) __dict__ 'özellikler veya '__getstate__') eşittir. – matthewwithanm