Python3.41A集

Python3.41A集,python,set,Python,Set,关于集合我有两个问题 一,。 所以当我读到集合是无序的,但当我开始用它们做实验时,我发现实际上存在某种有序的东西 如您所见,这一套中没有什么特别之处: >>> v_set ={88,11,1,33,21,3,7,55,37,8} >>> v_set {33, 1, 3, 37, 7, 8, 11, 21, 55, 88} 但这一个是不同的: >>> g_set={7,5,11,1,4,13,55,12,2,3,6,20,9,10} >

关于集合我有两个问题

一,。 所以当我读到集合是无序的,但当我开始用它们做实验时,我发现实际上存在某种有序的东西

如您所见,这一套中没有什么特别之处:

>>> v_set ={88,11,1,33,21,3,7,55,37,8}
>>> v_set
{33, 1, 3, 37, 7, 8, 11, 21, 55, 88}
但这一个是不同的:

>>> g_set={7,5,11,1,4,13,55,12,2,3,6,20,9,10}
>>> g_set
{1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 20, 55}
我猜,这是因为这一次我写下了更接近的数字,并且开始有意义地设置这些数字的升序

二,。 第二个问题是关于pop()。我读到没有办法控制用pop()方法删除哪个值,这是完全任意的。打赌当我使用pop()方法时,它总是(我从来没有看到过不同的情况)从集合的左侧取第一个项目

如你所见:

>>> v_set
{33, 1, 3, 37, 7, 8, 11, 21, 55, 88}
>>> v_set.pop()
33
>>> v_set.pop()
1
>>> v_set.pop()
3
>>> v_set.pop()
37
>>> v_set.pop()
7
>>> v_set.pop()
8
>>> v_set.pop()
11
>>> v_set.pop()
21
>>> v_set.pop()
55

那么它真的是完全任意的吗?

是的,根据定义,排序是任意的。即使项目以排序顺序存储,它仍然是任意的。“任意”意味着Python不承诺以任何特定方式对数据进行排序。因为内存是线性的,所以它必须使用某种顺序,但你永远不应该依赖于这种顺序,因为它可能会在没有通知的情况下被更改。(事实上,在Python的最新版本中,
集中的项目顺序是。)

第二个示例显示打印顺序与弹出顺序相同。这是有意义的:
repr
按照存储在内存中的顺序遍历项目,而
pop
显然会按照相同的顺序返回第一个项目。同样,您不能依赖于这一点:这是一个实现细节,如果Python开发人员想出了一种更快的方法来执行
pop
,他们就可以自由地破坏任何依赖
set
排序的代码


如果你想知道它是如何工作的,请仔细阅读哈希表。

这并不是完全随意的。但这并不重要

我们称该集合为无序,因为作为该代码的用户或客户端,您不能依赖于特定的顺序。然而,根据集合实现的细节,可能存在某种顺序

对于
pop()
,也是如此。很可能您所使用的python的特定实现具有逻辑,将导致明确的确定性结果。但是,您的代码可能与使用不同实现的python解释器一起使用<代码>随机元素
是实现的唯一保证


总之,该文档为您提供了一组保证,任何兼容的python实现都将遵循这些保证。您观察到的其他影响是实现细节,可能会随时更改

注意,元素的顺序也取决于插入的顺序。当发生碰撞时,您可以很容易地看到这一点:

In [4]: class Bad:
   ...:     def __init__(self, val, hash_val):
   ...:         self.val = val
   ...:         self.hash_val = hash_val
   ...:     def __str__(self):
   ...:         return 'Bad({0.val}, {0.hash_val})'.format(self)
   ...:     __repr__ = __str__
   ...:     def __eq__(self, other):
   ...:         return self.val == other.val
   ...:     def __hash__(self):
   ...:         return self.hash_val

In [5]: b1 = Bad(1, 1)
   ...: b2 = Bad(2, 1)
   ...: b3 = Bad(3, 2)

In [6]: {b1, b2, b3}
Out[6]: {Bad(2, 1), Bad(3, 2), Bad(1, 1)}

In [7]: {b2, b1, b3}
Out[7]: {Bad(1, 1), Bad(3, 2), Bad(2, 1)}
In [8]: b1 = Bad(1, 1)
   ...: b2 = Bad(2, 2)
   ...: b3 = Bad(3, 3)

In [9]: {b1, b2, b3}
Out[9]: {Bad(1, 1), Bad(2, 2), Bad(3, 3)}

In [10]: {b2, b1, b3}
Out[10]: {Bad(1, 1), Bad(2, 2), Bad(3, 3)}
正如您在
Out[6]
中所看到的,第一个元素是
Bad(2,1)
,最后一个元素是
Bad(1,1)
,而在
Out[7]
中,第一个元素是
Bad(1,1)
,最后一个元素是
Bad(2,1)

如果没有碰撞:

In [4]: class Bad:
   ...:     def __init__(self, val, hash_val):
   ...:         self.val = val
   ...:         self.hash_val = hash_val
   ...:     def __str__(self):
   ...:         return 'Bad({0.val}, {0.hash_val})'.format(self)
   ...:     __repr__ = __str__
   ...:     def __eq__(self, other):
   ...:         return self.val == other.val
   ...:     def __hash__(self):
   ...:         return self.hash_val

In [5]: b1 = Bad(1, 1)
   ...: b2 = Bad(2, 1)
   ...: b3 = Bad(3, 2)

In [6]: {b1, b2, b3}
Out[6]: {Bad(2, 1), Bad(3, 2), Bad(1, 1)}

In [7]: {b2, b1, b3}
Out[7]: {Bad(1, 1), Bad(3, 2), Bad(2, 1)}
In [8]: b1 = Bad(1, 1)
   ...: b2 = Bad(2, 2)
   ...: b3 = Bad(3, 3)

In [9]: {b1, b2, b3}
Out[9]: {Bad(1, 1), Bad(2, 2), Bad(3, 3)}

In [10]: {b2, b1, b3}
Out[10]: {Bad(1, 1), Bad(2, 2), Bad(3, 3)}
注意订单是如何没有改变的。(好的,散列被使用在
n
中,因此即使散列不同,也可能存在冲突,这取决于基础表的大小)

换句话说,这些值不足以确定
集合
元素的顺序,即使您知道它们是如何实现的。您还必须知道插入的顺序

一般来说,
set
s在单个解释器运行中有一个定义良好的顺序(由于python3.3+中的随机性),但是使用的顺序取决于执行的插入(值和插入顺序),并且是任意的,即在python3.5中,它们可以在不通知的情况下更改顺序,所以你不能依赖它


他们可以真正随机输出,但这只会增加开销,而不会带来任何好处。

请将您的帖子保留在一个问题上;您的第一个问题是重复的(集合只是字典,只有键,没有值)。
.pop()
的顺序与集合的迭代顺序一样“任意”;Python将其“随机”是没有意义的。非常喜欢您的答案,谢谢您的帮助!非常感谢您的解释!