Python 有一个内置的 hash() 函数,它非常快速且非常适合大多数用途:
>>> hash("dfds")
3591916071403198536
然后,您可以将其设为无符号:
>>> hashu=lambda word: ctypes.c_uint64(hash(word)).value
然后你可以把它变成一个 16 字节的十六进制字符串:
>>> hashu("dfds").to_bytes(8,"big").hex()
或 N*2 字节字符串,其中 N <= 8:
>>> hashn=lambda word, N : (hashu(word)%(2**(N*8))).to_bytes(N,"big").hex()
..ETC。如果你想让 N 大于 8 个字节,你可以散列两次。Python 的内置速度如此之快,除非您需要安全性,否则永远不值得将 hashlib 用于任何事情……而不仅仅是抗碰撞性。
>>> hashnbig=lambda word, N : ((hashu(word)+2**64*hashu(word+"2"))%(2**(N*8))).to_bytes(N,"big").hex()
最后,使用 urlsafe base64 编码来制作比“hex”更好的字符串给你
>>> hashnbigu=lambda word, N : urlsafe_b64encode(((hashu(word)+2**64*hash(word+"2"))%(2**(N*8))).to_bytes(N,"big")).decode("utf8").rstrip("=")
>>> hashnbigu("foo",16)
'ZblnvrRqHwAy2lnvrR4HrA'
注意事项:
请注意,在 Python 3.3 及更高版本中,此函数是随机的,不适用于某些用例。您可以使用 PYTHONHASHSEED=0 禁用此功能
请参阅https://github.com/flier/pyfasthash,了解不会破坏非加密应用程序的 CPU 的快速、稳定的哈希值。
不要在实际代码中使用这种 lambda 样式...写出来!并且在代码中填充诸如 2**32 之类的东西,而不是使它们成为常量是不好的形式。
最后,对于较小的应用程序来说,8 字节的抗碰撞性是可以的……如果条目少于一百万,您的碰撞几率 < 0.0000001%。那是一个 12 字节的 b64 编码字符串。但对于较大的应用程序可能还不够。
对于缓存中的 UUID/OID 等,16 个字节就足够了。