【问题标题】:Indeterministic sets in Python 2 and 3Python 2 和 3 中的不确定集
【发布时间】:2018-09-28 11:43:58
【问题描述】:

Python 2

集合是无序值的集合。如果我通过集合文字构造集合,例如

s = {'a', 'b', 'c'}

然后打印出来,我得到了一些乱序的元素。但是,在 Python 2.7 中,上面的示例似乎总是导致相同的排序:

print(s)  # set(['a', 'c', 'b']) in Python 2.7

Python 2.7 如何决定这个顺序?甚至'a''b''c' 的哈希值也不按生成顺序。

Python 3

在 Python 3.x(包括对 dict 键进行排序的 3.6)中,生成的顺序似乎是随机的,尽管在给定的 Python 进程中总是相同的。也就是说,只要我不重新启动 Python 解释器,反复重新构建集合文字总是会导致相同的顺序。

要检查多个 Python 进程的顺序,请考虑 bash 代码

(for _ in {1..50}; do python3 -c "s = {'a', 'b', 'c'}; print(s)"; done) | sort -u

这将(通常)显示 3 个元素的 6 种不同排列方式。用python(2) 切换出python3,我们只看到排序['a', 'c', 'b']。什么决定了 Python 3 中的顺序?

我发现对象的 hash 值在 Python 2 中是确定性的,而在 Python 3 中是随机的(尽管在 Python 进程中是恒定的)。我相信这是完整解释的关键。

编辑

正如 deceze 在他的评论中所写,我想知道 Python 是否明确地做了一些事情来实现这种随机化,或者它是否“免费”发生。

【问题讨论】:

  • 有什么意义?您不应该依赖集合或字典的特定顺序。如果你需要,你应该使用OrderedDict。此外,您发现的散列行为与它应该具有散列函数的属性一致。如果您需要确定性哈希,请实现您自己的。
  • 预计在确定性算法中会有一些顺序,除非 Python 不遗余力地故意随机化该顺序。
  • 虽然这些字符的完整哈希值不是按这个顺序排列的,但它们的低位是!对于基于散列的小型容器,python 只使用那些低位。
  • @Wombatz 谢谢,这是一个相当大的难题。

标签: python python-3.x python-2.7 set non-deterministic


【解决方案1】:

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'}

同样,您可以在 Python 2 中使用 -R flag 开启哈希随机化:

$ (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'])

请注意,您通常不希望将其关闭,因为启用哈希随机化有助于防止某些拒绝服务攻击。

【讨论】:

  • 记得把它重新打开 :)。不错的 +1!
  • 我想关闭它的主要原因是,在编写蒙特卡罗模拟时,我总是打印出 random.seed 的值,并提供一种在运行代码时指定种子的方法.这样,如果在模拟过程中发生了一些有趣的事情(错误或有趣的行为),我可以重新运行完全相同的轨迹,例如,更多的输出来调查。
猜你喜欢
  • 2010-10-04
  • 1970-01-01
  • 2023-03-10
  • 2018-01-23
  • 2016-03-04
  • 2019-12-27
  • 2019-02-22
  • 2015-06-21
  • 2014-04-12
相关资源
最近更新 更多