80 python hash google-app-engine
Windows XP,Python 2.5:
hash('http://stackoverflow.com') Result: 1934711907
Run Code Online (Sandbox Code Playgroud)
Google App Engine(http://shell.appspot.com/):
hash('http://stackoverflow.com') Result: -5768830964305142685
Run Code Online (Sandbox Code Playgroud)
这是为什么?我怎样才能有一个哈希函数,它可以在不同平台(Windows,Linux,Mac)上提供相同的结果?
Mik*_*cki 88
如文档中所述,内置的hash()函数不是为在外部某处存储结果哈希而设计的.它用于提供对象的哈希值,将它们存储在词典中等等.它也是特定于实现的(GAE使用Python的修改版本).查看:
>>> class Foo:
... pass
...
>>> a = Foo()
>>> b = Foo()
>>> hash(a), hash(b)
(-1210747828, -1210747892)
Run Code Online (Sandbox Code Playgroud)
如您所见,它们是不同的,因为hash()使用object的__hash__方法而不是'normal'哈希算法,例如SHA.
鉴于上述情况,理性选择是使用hashlib模块.
Sil*_*ost 55
在字典查找期间快速比较字典键
因此不保证它在Python实现中是相同的.
rew*_*ten 32
事实上,回应绝对不足为奇
In [1]: -5768830964305142685L & 0xffffffff
Out[1]: 1934711907L
Run Code Online (Sandbox Code Playgroud)
因此,如果您想获得有关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
Run Code Online (Sandbox Code Playgroud)
其中c_mul函数是"循环"乘法(没有溢出),如C中所示.
are*_*lek 16
大多数答案表明这是因为不同的平台,但还有更多.来自以下文件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
Run Code Online (Sandbox Code Playgroud)
而:
$ python -c "print(hash((1,2,3)))"
2528502973977326415
$ python -c "print(hash((1,2,3)))"
2528502973977326415
Run Code Online (Sandbox Code Playgroud)
另请参见环境变量PYTHONHASHSEED:
如果未设置,或设置为这个变量
random,随机值被用于接种的散列str,bytes和datetime对象.如果
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
Run Code Online (Sandbox Code Playgroud)
哈希结果在32位和64位平台之间变化
如果计算的散列在两个平台上应相同,请考虑使用
def hash32(value):
return hash(value) & 0xffffffff
Run Code Online (Sandbox Code Playgroud)
猜测,AppEngine正在使用64位的Python实现(-5768830964305142685不适合32位),你的Python实现是32位.您不能依赖于不同实现之间具有可比性的对象哈希值.
这是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
Run Code Online (Sandbox Code Playgroud)
小智 5
标志位怎么样?
例如:
十六进制值0xADFE74A5表示未签名2919134373和签名-1375832923.必须对Currect值进行签名(符号位= 1),但python将其转换为无符号,并且在从64位转换为32位后,我们的哈希值不正确.
小心使用:
def hash32(value):
return hash(value) & 0xffffffff
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
98300 次 |
| 最近记录: |