2

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

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评论中所建议的那样。此外,如果您使用控制台来复制它,请确保Rerun每次运行代码时都使用控制台。)


然而,当将上面的代码放在 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 次而不会更改。

为什么不改变?

4

2 回答 2

5

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

为了防止这些攻击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__(). 底部有一条注释(正是关于您的情况):

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

于 2015-08-23T09:18:12.140 回答
4

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

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

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

于 2015-08-23T09:03:05.577 回答