在python中,set.pop()是否确定?

时间:2012-05-03 13:06:29

标签: python set

我知道python集的元素没有排序。调用pop方法返回一个任意元素;我很好。

我想知道当集合具有相同的历史记录时,pop是否总是会返回相同的元素。当然,在python的一个版本中,我不介意python的不同版本/实现是否有自己的功能。特别是,我问的是python 2.7。在这种情况下,这不仅仅是api的实现问题。

我在游戏的程序性地下城生成器中使用了很多集合,我希望结果对于给定的种子具有确定性。

5 个答案:

答案 0 :(得分:24)

答案一般是 no。 @Christophe和@Marcin(联合国)帮助指向的python源显示元素按照它们在哈希表中出现的顺序弹出。因此,弹出顺序(可能是迭代顺序)确定性的,但仅适用于固定的哈希值。 根据{{​​3}}文档中的注意,数字的情况就是情况,但不是,这也恰好直接触及了你的问题:

  

默认情况下,str,bytes和datetime对象的哈希()值被“加盐”,并带有不可预测的随机值。尽管它们在单个Python进程中保持不变,但在重复调用Python之间无法预测它们。

     

[...]

     

更改散列值会影响dicts,集和其他映射的迭代顺序。 Python从未对这种排序做出保证(通常在32位和64位版本之间有所不同)。

编辑:正如@Marcin指出的那样,我引用的链接不适用于Python 2。 散列随机化__hash__默认情况下,Python 2.7没有故意的非确定性字符串散列。

通常,对于其散列不是其值的可重复函数的任何对象(例如,如果散列基于存储器地址),这是一个问题。但相反,如果您为集合中的对象定义自己的__hash__方法,则可以预期它们将以可重现的顺序返回。 (假设集合的历史和平台保持固定)。

答案 1 :(得分:6)

在内部,我认为情况类似于dict。该顺序由散列算法确定,在某些情况下将产生相同的结果。但是你不应该依赖它,因为一旦元素的数量变大,该集合将遇到冲突(即它的内部散列),最终导致不同的排序。

简而言之:不,set.pop()不具有确定性。不要假设任何订单,因为API明确说明了

  

设置对象是无序集合

答案 2 :(得分:4)

The documentation没有指明它必须是确定性的,因此你应该假设它不是。

答案 3 :(得分:1)

如果你想强迫决定论,你可以尝试像

这样的东西
value = min(my_set)
my_set.remove(value)

答案 4 :(得分:-1)

如果您真的针对某个特定版本的python,那么您可以查看源代码并测试其行为(但测试得好 - 考虑负载因素等)。

如果你想要可移植性,或者你发现set没有按要求执行,请使用ordereddict(这里是一个:http://code.activestate.com/recipes/576693/;还有很多其他的,所以找一个你喜欢的外观),并将其作为一组进行调整。

更新:这是一个有序集:http://packages.python.org/Brownie/api/datastructures.html#brownie.datastructures.OrderedSet