neolee / wop-community

29 stars 19 forks source link

关于 list() 中 set、dict 两种数据容器返回其元素的列表时顺序的疑问 #225

Closed Sincere-io closed 4 years ago

Sincere-io commented 4 years ago

老师教材中描述set和dict这两种数据容器返回的列表顺序不可预测,是随机的吗?如果是随机的为什么每次运行的顺序都不变?


print(list())
print(list('aeiou'))
print(list(('a', 'e', 'i', 'o', 'u')))
print(list({'a', 'e', 'i', 'o', 'u'}))
print(list({'a': 1, 'e': 2, 'i': 3, 'o': 4, 'u': 5}))
[]
['a', 'e', 'i', 'o', 'u']
['a', 'e', 'i', 'o', 'u']
['i', 'e', 'u', 'o', 'a']
['a', 'e', 'i', 'o', 'u']
xuzhengfu commented 4 years ago

https://github.com/neolee/wop-community/issues/221#issue-674268030

Sincere-io commented 4 years ago

请问我这里print(list({'a', 'e', 'i', 'o', 'u'}))这行代码每次运行返回的列表顺序都不变,也是这个原因吗?

221 (comment)

xuzhengfu commented 4 years ago

对于 print(list({'a', 'e', 'i', 'o', 'u'})) 这一句,你上面的返回结果是:['i', 'e', 'u', 'o', 'a']

这顺序不是变了么……

Sincere-io commented 4 years ago

不是每次运行随机顺序吗?好吧。

xuzhengfu commented 4 years ago

这个问题可能需要去看 set 这个数据容器的源代码才能彻底搞清楚。

不过,有更为简单一点的方法。

我们已经知道:python 的 4 个数据容器都是 iterable;我们还知道:它们的迭代器会从 iterable 数据集中取出下一个元素。

那我们不妨来看看,set 这个数据容器的迭代器究竟是不是随机取回下一个元素的?

x = {'a', 'e', 'i', 'o', 'u'}
x_iterator = x.__iter__()

for item in range(len(x)):
    print(x_iterator.__next__(), end=' ')

我把以上代码运行了 10 次,得到的结果是:

e a u o i 
i e a o u 
a u e i o 
i e a u o 
a u o i e 
e o i u a 
a i o u e 
o a u e i 
a e o i u 
i e a u o 

「set 是无序容器」这一点,在以上的「猜想-验证」过程中得到了充分的体现。

Sincere-io commented 4 years ago
x = {'a', 'e', 'i', 'o', 'u'}
x_iterator = x.__iter__()

for item in range(len(x)):
    print(list(x_iterator.__next__()))

@Xuzhengfu 以上代码是在Windows 10 下多次运行得到的结果:

['u']
['a']
['i']
['o']
['e']

多次运行的顺序并没有改变。

xuzhengfu commented 4 years ago

你是不是在 jupyter lab 里运行的?我在 jupyter lab 里运行也出现了 ”看不到随机性“ 的情况。

你把上面的代码保存到一个 xxxx.py 文件中,然后在「命令行」里用 python3 xxxx.py 再看看结果。

neolee commented 4 years ago

关于 set 和 dict 容器的所谓“无序”包含两层含义:

  1. 容器内的元素没有序号的概念,没法通过顺序来访问其元素;
  2. 这些容器迭代时输出元素的顺序可能变化也可能不变,但这是由容器内部实现决定的,你任何时候都不应假定容器内元素的顺序是不变的,