设置迭代顺序因运行而异

Adr*_*thy 20 python iteration set

为什么Python集的迭代顺序(具有相同的内容)因运行而异,以及从运行到运行使其一致的选项是什么?

我知道Python集的迭代顺序是任意的.如果我将'a','b'和'c'放入一个集合然后迭代它们,它们可能会以任何顺序返回.

我观察到的是,在一个程序的运行中,顺序保持不变.也就是说,如果我的程序连续两次迭代同一个集合,那么我两次都得到相同的顺序.但是,如果我连续两次运行程序,则顺序会从运行更改为运行.

不幸的是,这打破了我的一个自动化测试,它简单地比较了我的程序的两次运行的输出.我不关心实际的顺序,但我希望它在运行之间保持一致.

我提出的最佳解决方案是:

  1. 将该集复制到列表.
  2. 对列表应用任意排序.
  3. 迭代列表而不是集合.

有更简单的解决方案吗?

注意:我在StackOverlow上发现了类似的问题,但是没有一个能解决从运行到运行获得相同结果的特定问题.

Bri*_*ane 15

在两个集合上使用symmetric_difference(^)运算符来查看是否存在任何差异:

In [1]: s1 = set([5,7,8,2,1,9,0])
In [2]: s2 = set([9,0,5,1,8,2,7])
In [3]: s1
Out[3]: set([0, 1, 2, 5, 7, 8, 9])
In [4]: s2
Out[4]: set([0, 1, 2, 5, 7, 8, 9])
In [5]: s1 ^ s2
Out[5]: set()
Run Code Online (Sandbox Code Playgroud)


Tur*_*tle 13

你想要的是不可能的.任意意味着任意.

我的解决方案与您的解决方案相同,如果您希望能够将其与另一个进行比较,则必须对该集进行排序.

  • 我想我认为任意意味着它取决于内容,而不是月亮的相位. (9认同)
  • 即使从运行到运行一致,也不能保证从机器到机器,python版本到python版本,cpython和jython等一致. (6认同)
  • 并且'相同的内容'也不能保证,即使在同一台机器上的相同Python构建中也是如此.根据哈希值插入项目.当多个项目具有相同的哈希值时,它们会根据插入的顺序插入到不同的位置.项目的删除会导致更多不同的排序.然后有一些项目的哈希值取决于它们的内存位置,这使得它在运行之间不同.除了使用`sorted()`以便编写3个步骤的方便方法之外,你无能为力. (2认同)

Adr*_*thy 11

设置迭代顺序从一次运行更改为运行的原因似乎是因为默认情况下Python使用哈希种子随机化.(参见命令选项-R.)因此,设置迭代不仅是任意的(因为散列),而且是非确定性的(因为随机种子).

您可以通过为解释器设置环境变量PYTHONHASHSEED来覆盖具有固定值的随机种子.使用从run到run的相同种子意味着set iteration仍然是任意的,但现在它是确定性的,这是所需的属性.

散列种子随机化是一种安全措施,使对手难以提供将导致病态行为的输入(例如,通过创建大量散列冲突).对于单元测试,这不是问题,因此在运行测试时覆盖散列种子是合理的.


Ned*_*der 5

集合的迭代顺序不仅取决于其内容,还取决于项目插入集合的顺序,以及沿途是否有删除.因此,您可以使用不同的插入和删除创建两个不同的集合,最后使用相同的集合,但具有不同的迭代顺序.

正如其他人所说:如果你关心集合的顺序,你必须从中创建一个排序列表.

  • Thomas Wouters在上面的评论中指出,有些类在散列函数中使用id(),这意味着对象的散列取决于它的内存地址,谁知道可能会有什么不同.如果你正在使用自己的类,你可以编写自己的__hash__函数来摆脱一些不确定性,但你最好还是简单地对结果进行排序. (4认同)

Oli*_*oux 5

你的问题变成了两个问题:A)如何在你的具体情况下比较“两次运行的输出”;B) 集合中迭代顺序的定义是什么。也许你应该区分它们,并在适当的情况下将 B) 作为一个新问题发布。我来回答A。

恕我直言,在您的情况下使用排序列表并不是一个非常干净的解决方案。您应该决定是否一劳永逸地关心迭代顺序并使用适当的结构。

1) 您想要比较两个集合,看看它们是否具有相同的内容,无论顺序如何。那么集合上的简单 == 运算符似乎是合适的。请参阅python2 集python3 集

或者 2) 您想要检查元素是否以相同的顺序插入。但是,只有当插入顺序对库的用户有某种影响时,这才显得合理,在这种情况下,使用集合类型可能一开始就不合适。换句话说,目前尚不清楚“比较两次运行的输出”到底是什么意思以及为什么要这样做。

在所有情况下,我怀疑排序列表在这里是否合适。