Built in python hash() function
Windows XP,Python 2.5:P></
1 | hash('http://stackoverflow.com') Result: 1934711907 |
谷歌应用程序引擎(http:/ / / shell.appspot.com):P></
1 | hash('http://stackoverflow.com') Result: -5768830964305142685 |
为什么is that?我怎么能在我的哈希函数相同的结果会给它在不同的平台(Windows,Linux,Mac)?P></
如文档中所述,内置hash()函数不是为在外部某个地方存储产生的哈希而设计的。它用于提供对象的散列值,将其存储在字典等中。它也是特定于实现的(GAE使用修改后的Python版本)。退房:
1 2 3 4 5 6 7 | >>> class Foo: ... pass ... >>> a = Foo() >>> b = Foo() >>> hash(a), hash(b) (-1210747828, -1210747892) |
如您所见,它们是不同的,因为hash()使用对象的
鉴于上述情况,合理的选择是使用hashlib模块。
使用hashlib作为
quickly compare dictionary keys during a dictionary lookup
号
因此不能保证它在整个Python实现中都是相同的。
这一反应绝对不足为奇:事实上
1 2 | In [1]: -5768830964305142685L & 0xffffffff Out[1]: 1934711907L |
号
因此,如果您想在ASCII字符串上获得可靠的响应,只需获得较低的32位作为
另一方面,对于没有明确定义
对于ASCII字符串,它的工作原理只是因为散列是根据构成字符串的单个字符计算的,如下所示:
1 2 3 4 5 6 7 8 9 10 11 | 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 |
其中,
大多数答案表明,这是因为不同的平台,但还有更多。根据
By default, the
__hash__() values ofstr ,bytes and
datetime objects are"salted" with an unpredictable random value.
Although they remain constant within an individual Python process,
they are not predictable between repeated invocations of Python.This is intended to provide protection against a denial-of-service
caused by carefully-chosen inputs that exploit the worst case
performance of a dict insertion, O(n2) complexity. See
http://www.ocert.org/advisories/ocert-2011-003.html for details.Changing hash values affects the iteration order of
dicts ,sets
and other mappings. Python has never made guarantees about this
ordering (and it typically varies between 32-bit and 64-bit builds).
号
即使在同一台机器上运行,在调用时也会产生不同的结果:
1 2 3 4 | $ python -c"print(hash('http://stackoverflow.com'))" -3455286212422042986 $ python -c"print(hash('http://stackoverflow.com'))" -6940441840934557333 |
。
而:
1 2 3 4 | $ python -c"print(hash((1,2,3)))" 2528502973977326415 $ python -c"print(hash((1,2,3)))" 2528502973977326415 |
另见环境变量
If this variable is not set or set to
random , a random value is used
to seed the hashes ofstr ,bytes anddatetime objects.If
PYTHONHASHSEED is set to an integer value, it is used as a fixed
seed for generating thehash() of the types covered by the hash
randomization.Its purpose is to allow repeatable hashing, such as for selftests for
the interpreter itself, or to allow a cluster of python processes to
share hash values.The integer must be a decimal number in the range
[0, 4294967295] .
Specifying the value0 will disable hash randomization.
号
例如:
1 2 3 4 5 | $ export PYTHONHASHSEED=0 $ python -c"print(hash('http://stackoverflow.com'))" -5843046192888932305 $ python -c"print(hash('http://stackoverflow.com'))" -5843046192888932305 |
。
哈希结果在32位和64位平台之间变化
如果两个平台上的计算散列值相同,则考虑使用
1 2 | def hash32(value): return hash(value) & 0xffffffff |
。
这是Google在生产python 2.5时使用的哈希函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 |
。
大概,AppEngine使用的是64位的Python实现(5768830964305142685不适合32位),而您的Python实现是32位。不能依赖于对象散列在不同实现之间有意义地可比较。
符号位呢?
例如:
十六进制值
小心使用:
1 2 | def hash32(value): return hash(value) & 0xffffffff |
。
字符串的多项式哈希。
1 2 3 4 5 6 | mod=1000000009 def hash(s): result=0 for c in s: result = (result * 239 + ord(c)) % mod return result % mod |
。
pythonhashseed的值可用于初始化哈希值。
尝试:
1 | PYTHONHASHSEED python -c 'print(hash('http://stackoverflow.com'))' |
它可能只是请求操作系统提供的函数,而不是自己的算法。
正如其他评论所说,使用hashlib或编写自己的哈希函数。