从Python 3.3开始,散列算法是不确定的,以避免某种攻击。这对于Web服务器来说很好,但在调试程序时却很麻烦:每次运行脚本时,dict内容都以不同的顺序迭代。
python的一些早期版本有一个-R
标志,用于启用散列随机化,但现在它是默认行为,该标志没有被其相反的标志所取代。通过设置环境变量PYTHONHASHSEED
可以禁用随机化:
Python籽
如果未设置此变量或将其设置为random,则使用随机值作为str、bytes和datetime对象的哈希的种子。
如果PYTHONHASHSEED设定为整数值,则会当做固定的种子,用来产生杂凑随机化所涵盖之型别的杂凑()。
问题是必须在启动python进程之前设置此变量。我试过用os.putenv()
或os.environ
来设置它,但这些似乎对哈希方法没有影响。这并不太令人惊讶:我不希望python在每次设置或字典查找之前都检查环境!所以,问题依然存在:
有没有办法让python程序禁用自己的散列随机化?
3条答案
按热度按时间nwnhqdif1#
很不幸,我怀疑这是不可能的。查看
test_hash.py
,HashRandomizationTests
类及其后代被添加到引入这种行为的提交中。他们通过修改环境并启动一个显式设置PYTHONHASHSEED
的新进程来测试散列行为。也许你可以试着复制这种模式。我还注意到你说“* 每次我运行脚本时,dict内容都以不同的顺序迭代。*”-我想你知道
collections.OrderedDict
,对吧?这是获得可靠的哈希迭代的正常方法。如果你愿意在你的shell环境中设置这个值,你也可以把你的python调用 Package 在一个bash脚本中,例如。
字符串
这样就避免了需要操纵整个环境,只要您对 Package 器脚本没问题。
或者只是在命令行上传递值:
型
koaltpgm2#
也许唯一/最干净的方法是在你的程序开始之前添加这个:
字符串
如果缺少
PYTHONHASHSEED
,它会将其设置为零,并将当前程序替换为一个新的,提供相同的参数集。根据os.execv
:这些函数都执行一个新程序,取代当前进程;他们不会回来。在Unix上,新的可执行文件被加载到当前进程中,并且将具有与调用者相同的进程ID。错误将报告为OSErerror异常。
立即替换当前进程。打开的文件对象和描述符不会刷新,因此如果这些打开的文件上可能有缓冲的数据,您应该在调用exec* 函数之前使用sys.stdout.flush()或os.fsync()刷新它们。
ep6jt1vc3#
除了字典顺序,散列随机化也可能破坏直接使用
hash()
的现有代码。在这种情况下,解决了问题的一个变通方法是替换字符串
与
型
hashlib.sha512()
个hash.hexdigest()
个注意,数字的范围和是否包括负数是不同的。后一种代码给出了一个更大的数字范围,并且散列冲突是极不可能的。
要再现与
hash()
相同的64位范围,可以将十六进制数减少到16(每个数4位),并将结果移位到最小的负64位数开始:型
或者,可以使用8个字节并使用
int.from_bytes
:型