Python冻结集合的持久化哈希

5

如何将Python frozenset对象的嵌套转换为唯一的整数,使其在不同的Python会话和平台上保持相同?

例如,在不同平台上使用hash()函数得到的值是不同的。

32位

Python 2.6.5 (r265:79063, Apr 16 2010, 13:09:56) 
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a=frozenset([frozenset([1,2,3]),frozenset(['a','b','c'])]);
>>> hash(a)
1555175235

64位

Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41) 
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a=frozenset([frozenset([1,2,3]),frozenset(['a','b','c'])]);
>>> hash(a)
-6076998737938213053

相关链接:https://dev59.com/wr3pa4cB1Zd3GeqPjbPz - Albert
2个回答

8
你如何将Python frozenset对象的嵌套转换为唯一的整数,在Python会话和平台之间保持相同?
据我所知,哈希值不能保证唯一。实际上,在用于查找表(例如字典)的哈希冲突中非常普遍。
话虽如此。如果您想要在平台之间使用一致的、非唯一的“哈希”,我建议尝试使用标准库hashlib。我没有在不同的平台上尝试过它,但我相信其中大多数实现的算法(例如MD5)都是与平台无关的。
我将使用排序后的集合的pickled版本来提供哈希算法,以确保用于哈希的字符串始终相同。

编辑:想要添加一个基本的例子:

>>> import cPickle as pkl
>>> import hashlib as hl
>>> s = frozenset([1,2,3])
>>> p = pkl.dumps(sorted(s))  #make sure you use the same pickle protocol on all platform!
'(lp1\nI1\naI2\naI3\na.'
>>> h = hl.md5(p)
<md5 HASH object @ 0xb76fb110>
>>> h.digest()
"\x89\xaeG\x1d'\x83\xa5\xbd\xac\xa7\x1c\xd9\x1d/2t"  #this should be consistent

就这个问题而言,我已经检查了在32位和64位平台上冻结集合的md5校验和是相同的。 - jcollado
1
一个无序类型的腌制是否保证在所有平台上都能腌制成相同的东西?我不太愿意相信它会。我可能会将集合中的元素取出放入列表中,并在腌制之前对它们进行排序。 - dstromberg
谢谢。我需要递归遍历我的嵌套frozensets,并将它们转换为排序列表,但除此之外,这应该可以工作。 - Cerin
1
@dstromberg,我不认为是这样的。我想这就是为什么他首先对frozenset进行排序的原因。 - Cerin
不能保证在两个不同的会话/平台中pickle相同的对象将产生相同的文件 - 即使这些对象是有序的。因此,除非您喜欢在未来解决非常困难的调试难题,否则不应该依赖它。也许递归排序和repr可能有效,因为排序对象的repr可能是唯一定义的,但我既没有尝试过,也没有思考过足够的内容来确信它会起作用。 - max

0

你也可以创建自己的哈希函数:

def hash(fs):
    res = 1
    for v in fs:
        res = (res*31 + v) % 2**30
    return res

这并不一定是唯一的,但它与内置的 set 哈希一样好,并且您可以在各个平台上完全控制其结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接