当前位置:  开发笔记 > 编程语言 > 正文

内置python hash()函数

如何解决《内置pythonhash()函数》经验,为你挑选了8个好方法。

Windows XP,Python 2.5:

hash('http://stackoverflow.com') Result: 1934711907

Google App Engine(http://shell.appspot.com/):

hash('http://stackoverflow.com') Result: -5768830964305142685

这是为什么?我怎样才能有一个哈希函数,它可以在不同平台(Windows,Linux,Mac)上提供相同的结果?



1> Mike Hordeck..:

如文档中所述,内置的hash()函数不是为在外部某处存储结果哈希设计的.它用于提供对象的哈希值,将它们存储在词典中等等.它也是特定于实现的(GAE使用Python的修改版本).查看:

>>> class Foo:
...     pass
... 
>>> a = Foo()
>>> b = Foo()
>>> hash(a), hash(b)
(-1210747828, -1210747892)

如您所见,它们是不同的,因为hash()使用object的__hash__方法而不是'normal'哈希算法,例如SHA.

鉴于上述情况,理性选择是使用hashlib模块.



2> SilentGhost..:

使用hashlib作为hash() 被设计用于:

在字典查找期间快速比较字典键

因此不保证它在Python实现中是相同的.


基准:`hash`95 ns,`binascii.crc32` 570 ns,`hashlib.md5.digest()`1.42 us,`murmur.string_hash` 234 ns
与通用哈希函数(如Jenkins,Bernstein,FNV,MurmurHash等)相比,它们实际上非常慢.如果你想建立自己的哈希表结构,我建议你看看uthash.h http://uthash.sourceforge.net/
`hashlib`中的哈希函数对非加密使用有点慢吗?

3> rewritten..:

事实上,回应绝对不足为奇

In [1]: -5768830964305142685L & 0xffffffff
Out[1]: 1934711907L

因此,如果您想获得有关ASCII字符串的可靠响应,请将低32位作为uint.字符串的哈希函数是32位安全且几乎可移植.

另一方面,您根本不能依赖于hash()任何未明确定义__hash__方法不变的对象.

在ASCII字符串上,它的工作原理只是因为哈希是在形成字符串的单个字符上计算的,如下所示:

class string:
    def __hash__(self):
        if not self:
            return 0 # empty
        value = ord(self[0]) << 7
        for char in self:
            value = c_mul(1000003, value) ^ ord(char)
        value = value ^ len(self)
        if value == -1:
            value = -2
        return value

其中c_mul函数是"循环"乘法(没有溢出),如C中所示.



4> arekolek..:

大多数答案表明这是因为不同的平台,但还有更多.来自以下文件object.__hash__(self):

默认情况下,该__hash__()str,bytes并且 datetime对象是"咸"不可预测的随机值.虽然它们在单个Python进程中保持不变,但是在重复调用Python之间它们是不可预测的.

这旨在提供针对由精心选择的输入引起的拒绝服务的保护,该输入利用dict插入的最坏情况性能,O(n²)复杂度.有关详细信息,请参见 http://www.ocert.org/advisories/ocert-2011-003.html.

更改哈希值影响的迭代顺序dicts,sets 和其他的映射.Python从未对此排序做出保证(通常在32位和64位版本之间有所不同).

即使在同一台机器上运行,也会在调用过程中产生不同的结果:

$ python -c "print(hash('http://stackoverflow.com'))"
-3455286212422042986
$ python -c "print(hash('http://stackoverflow.com'))"
-6940441840934557333

而:

$ python -c "print(hash((1,2,3)))"
2528502973977326415
$ python -c "print(hash((1,2,3)))"
2528502973977326415

另请参见环境变量PYTHONHASHSEED:

如果未设置,或设置为这个变量random,随机值被用于接种的散列str,bytesdatetime对象.

如果PYTHONHASHSEED设置为整数值,则将其用作固定种子,以生成hash()散列随机化所涵盖的类型.

其目的是允许可重复的散列,例如解释器本身的自我测试,或允许一组python进程共享散列值.

整数必须是范围内的十进制数[0, 4294967295].指定该值0将禁用散列随机化.

例如:

$ export PYTHONHASHSEED=0                            
$ python -c "print(hash('http://stackoverflow.com'))"
-5843046192888932305
$ python -c "print(hash('http://stackoverflow.com'))"
-5843046192888932305


这仅适用于Python 3.x,但由于Python 3是现在和未来,这是唯一解决此问题的答案,+ 1.

5> Tzury Bar Yo..:

哈希结果在32位和64位平台之间变化

如果计算的散列在两个平台上应相同,请考虑使用

def hash32(value):
    return hash(value) & 0xffffffff



6> George V. Re..:

猜测,AppEngine正在使用64位的Python实现(-5768830964305142685不适合32位),你的Python实现是32位.您不能依赖于不同实现之间具有可比性的对象哈希值.



7> Andrin von R..:

这是Google在python 2.5的生产中使用的哈希函数:

def c_mul(a, b):
  return eval(hex((long(a) * b) & (2**64 - 1))[:-1])

def py25hash(self):
  if not self:
    return 0 # empty
  value = ord(self[0]) << 7
  for char in self:
    value = c_mul(1000003, value) ^ ord(char)
  value = value ^ len(self)
  if value == -1:
    value = -2
  if value >= 2**63:
    value -= 2**64
  return value


你能分享一下这个哈希函数的用途和原因吗?

8> 小智..:

标志位怎么样?

例如:

十六进制值0xADFE74A5表示未签名2919134373和签名-1375832923.必须对Currect值进行签名(符号位= 1),但python将其转换为无符号,并且在从64位转换为32位后,我们的哈希值不正确.

小心使用:

def hash32(value):
    return hash(value) & 0xffffffff

推荐阅读
凹凸曼00威威_694
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有