【问题标题】:Why is set order maintained sometimes?为什么有时会保持固定顺序?
【发布时间】:2015-11-16 20:22:01
【问题描述】:

运行此代码时,结果会按预期变化,因为集合是无序的:

my_set_1 = {'a','b','c',}
print([i for i in my_set_1])

也就是说,多次运行会给出不同的列表,例如

['a', 'c', 'b']
['b', 'a', 'c']
['a', 'c', 'b']
['c', 'b', 'a']

等等

(注意:如果您没有 PYTHONHASHSEED=random,则可能会得到相同的结果,如 cmets 中所建议的那样。此外,如果您使用控制台来复制它,确保每次运行代码时重新运行控制台。)


然而,当将上面的代码放在 for 循环中时,结果相当令人惊讶:

for i in range(10):
    my_set_1 = {'a','b','c',}
    print([i for i in my_set_1])
# Prints: 
# ['a', 'c', 'b']
# ['a', 'c', 'b']
# ['a', 'c', 'b']
# ....

for 循环的单次运行将打印相同的列表。重新运行 for 循环可以打印不同的列表(例如 ['c', 'b', 'a']),但仍会打印 10 次而不会更改。

为什么不改变?

【问题讨论】:

  • 我的测试似乎表明 set 确实在运行之间保持顺序(相同的项目,未修改),它只是不能保证特定的顺序。无法重现您的第一个集合语句,从而在列表理解运行中产生不同的排序。
  • @ReutSharabani 您是否在控制台中运行该代码?如果是这样,请在模块中尝试此代码并运行该模块。
  • set中的顺序是任意的。
  • 你能提供一个的代码来说明问题吗?
  • 他们没有PYTHONHASHSEED=random,这就是他们无法复制的原因。可能您可以在答案中注明。

标签: python python-3.x for-loop set unordered


【解决方案1】:

@ReblochonMasque 有一个正确的观点:set 基于哈希表,如果运行之间计算的哈希相同,则运行之间的顺序相同。然而,这种行为很容易受到attacks 的攻击。

为了防止这些攻击,引入了特殊变量PYTHONHASHSEED。当它设置为 random 时,每次运行 Python 都会为相同的项目生成不同的哈希值。这就是为什么你会得到不同的顺序。

要检查这一点,您可以将PYTHONHASHSEED 设置为相同的数字来运行您的程序。运行之间的顺序将相同。

$ export PYTHONHASHSEED=random
$ python t.py
['a', 'b', 'c']
$ python t.py
['a', 'c', 'b']
$ python t.py
['c', 'b', 'a']
$ export PYTHONHASHSEED=4
$ python t.py
['a', 'b', 'c']
$ python t.py
['a', 'b', 'c']
$ python t.py
['a', 'b', 'c']

如果您查看object.__hash__()。底部有一个注释(正是关于您的情况):

注意 默认情况下,strbytesdatetime 对象的 __hash__() 值是用不可预测的随机值“加盐”的。尽管它们在单个 Python 进程中保持不变,但它们在 Python 的重复调用之间是不可预测的。

【讨论】:

    【解决方案2】:

    您不应期望集合的顺序会改变;从某种意义上说,集合是无序的,即顺序不是不变的,即无法保证它不会改变。

    实现是哈希表(字典)的形式;只要没有键冲突,顺序可能不会改变,但没有任何意义。也无法预测是否或何时会发生。

    从实验中得出结论时要小心:您得到的结果无法预测,并且取决于您运行时系统的状态。它们也不会跨平台、python 版本等...

    【讨论】:

      猜你喜欢
      • 2018-08-01
      • 1970-01-01
      • 2021-04-14
      • 2020-03-25
      • 1970-01-01
      • 1970-01-01
      • 2020-02-16
      • 2014-10-28
      相关资源
      最近更新 更多