jmd*_*_dk 0 python set non-deterministic python-2.7 python-3.x
集合是无序值的集合.如果我通过set literal构造一个集合,例如
s = {'a', 'b', 'c'}
Run Code Online (Sandbox Code Playgroud)
然后打印它,我得到了一些乱序的元素.但是,似乎在Python 2.7中,上面的示例总是产生相同的顺序:
print(s) # set(['a', 'c', 'b']) in Python 2.7
Run Code Online (Sandbox Code Playgroud)
Python 2.7如何决定这种排序?即使的哈希值'a','b'而'c'不是产生的顺序.
在Python 3.x(包括dict按键排序的3.6 )中,生成的顺序似乎是随机的,但在给定的Python进程中总是相同的.也就是说,只要我不重启Python解释器,反复重建set literal就会导致相同的顺序.
要检查多个Python进程的排序,请考虑bash代码
(for _ in {1..50}; do python3 -c "s = {'a', 'b', 'c'}; print(s)"; done) | sort -u
Run Code Online (Sandbox Code Playgroud)
这将(通常)显示3种元素可以排列的6种不同方式.python3用python(2)切换,我们只看到排序['a', 'c', 'b'].是什么决定了Python 3的排序?
我发现hash在Python 2中,对象的值是确定性的,而在Python 3中是随机的(虽然在Python过程中是常量).我确信这是完整解释的关键.
正如deceze在他的评论中写道,我想知道Python是否明确地做了一些事情来实现这种随机化,或者它是否"免费"发生.
Python 3(从Python 3.3开始)差异的原因是默认情况下启用了哈希随机化,您可以通过将PYTHONHASHSEED环境变量设置为固定值来关闭它:
$ export PYTHONHASHSEED=0
$ (for _ in {1..50}; do python3 -c "s = {'a', 'b', 'c'}; print(s)"; done) | sort -u
{'a', 'b', 'c'}
Run Code Online (Sandbox Code Playgroud)
同样,您可以使用-R标志在Python 2中打开哈希随机化:
$ (for _ in {1..50}; do python2 -R -c "s = {'a', 'b', 'c'}; print(s)"; done) | sort -u
set(['a', 'b', 'c'])
set(['a', 'c', 'b'])
set(['b', 'c', 'a'])
set(['c', 'b', 'a'])
Run Code Online (Sandbox Code Playgroud)
注意,您通常不希望将其关闭,因为启用了哈希随机化有助于防止某些拒绝服务攻击.