我知道 python 集合的元素没有排序。调用pop方法返回任意元素;我很好。
我想知道的是,当集合具有相同的历史时,pop 是否总是返回相同的元素。当然,在一个版本的 python 中,我不介意 python 的不同版本/实现是否做自己的事情。特别是,我问的是python 2.7。在这种情况下,这不仅仅是 api 的实现问题。
我在游戏的程序地牢生成器中使用了很多集合,我希望结果对于给定的种子是确定的。
一般来说,答案是否定的。@Christophe 和 @Marcin (un) 有用地指出的 python 源代码显示元素按照它们在哈希表中出现的顺序弹出。因此,弹出顺序(可能是迭代顺序)是确定性的,但仅适用于固定的哈希值。根据文档中的注释,数字就是这种情况,但字符串不是这种情况,顺便说一下,它也直接涉及您的问题:__hash__
请注意,默认情况下,str、bytes 和 datetime 对象的hash () 值是用不可预测的随机值“加盐”的。尽管它们在单个 Python 进程中保持不变,但它们在 Python 的重复调用之间是不可预测的。
[ ... ]
更改哈希值会影响 dicts、sets 和其他映射的迭代顺序。Python 从未对这种顺序做出保证(它通常在 32 位和 64 位版本之间变化)。
编辑:正如@Marcin 指出的那样,我引用的链接不适用于 Python 2。哈希随机化成为 Python 3.3 的默认设置。默认情况下,Python 2.7 没有有意的非确定性字符串散列。
通常,对于散列不是其值的可重复函数的任何对象(例如,如果散列基于内存地址),这都是一个问题。但相反,如果您为集合中的对象定义自己的__hash__
方法,则可以预期它们将以可重现的顺序返回。(前提是该系列的历史和平台保持不变)。
在内部我认为情况类似于dict
。顺序由哈希算法确定,在某些情况下会产生相同的结果。但是你不应该依赖它,因为一旦元素数量变大,集合就会遇到冲突(即它的内部散列),最终导致不同的排序。
简而言之:不,set.pop()
不是确定性的。不要假设任何顺序,因为 API 明确指出,
集合对象是无序集合
该文档没有指定它必须是确定性的,因此您应该假设它不是。
如果你想强制确定性,你可以尝试类似
value = min(my_set)
my_set.remove(value)
如果您确实针对某个特定版本的 python,那么您可以查看源代码并测试其行为(但测试良好 - 考虑负载因素等)。
如果您想要便携性,或者您发现set
没有按要求执行,请使用有序字典(这里有一个:http ://code.activestate.com/recipes/576693/ ;还有很多其他的,所以找一个你喜欢的样子of),并将其改编为一组。
更新:这是一个有序集:http ://packages.python.org/Brownie/api/datastructures.html#brownie.datastructures.OrderedSet