[从Python 3.3开始,哈希算法是不确定的salted,以避免某种攻击。这对Web服务器来说很好,但是在尝试调试程序时会很痛苦:每次运行脚本时,dict的内容都会以不同的顺序进行迭代。
某些较早的python版本具有用于[[enabling散列随机化的-R
标志,但是现在它是默认行为,该标志尚未被其相反的地方代替。可以通过设置环境变量PYTHONHASHSEED
来禁用随机化:
如果未将此变量设置为随机变量,则使用随机值来播种str,bytes和datetime对象的哈希值。如果将PYTHONHASHSEED设置为整数值,则它将用作生成散列随机化所覆盖类型的hash()的固定种子。PYTHONHASHSEED
陷阱是必须在启动python进程之前设置此变量。我试图用PYTHONHASHSEED
或os.putenv()
进行设置,但是这些似乎对哈希方法没有影响。这并不奇怪:我不希望python在每个单独的集合或字典查找之前检查环境!因此,问题仍然存在:
Python程序是否有办法禁用自己的哈希随机化?
os.environ
,将test_hash.py
类及其后代添加到test_hash.py
中。他们通过修改环境并通过显式设置HashRandomizationTests
来启动新进程来测试哈希行为。您可以尝试复制该模式。[我也刚刚注意到您说:“
每次运行脚本时,字典内容都会以不同的顺序进行迭代。”-我假设您知道commit that introduced this behavior,对吗?这是获得可靠的哈希迭代的正常方法。
PYTHONHASHSEED
只要您可以使用包装脚本,就可以避免操纵整个环境。或者甚至只是在命令行上传递值:
collections.OrderedDict
的现有代码。在这种情况下,为我解决了问题的一种解决方法是替换#! /bin/bash
export PYTHONHASHSEED=0
# call your python program here
与
$ PYTHONHASHSEED=0 python YOURSCRIPT.py
对于Python 3,标准字符串需要类似`mystring.encode('utf-8')的转换。 (我正在使用字节字符串。)
请注意,数字范围和是否包含负数是不同的。后面的代码提供了更大的数字范围,并且散列冲突极不可能发生。
要重现与hash()
相同的64位范围,可以将十六进制数字的数量减少到16(每位4位),并将结果偏移为最小的负64位数字开始。
hash(mystring)
或者,可以占用8个字节并使用int(hashlib.sha512(mystring).hexdigest(), 16)
:
hash()