是python';s";“设置”;马厩?
当回答另一个SO问题()时,问题出现了 当我在一个python集上迭代几次(在调用之间不改变它)时,我能假定它总是以相同的顺序返回元素吗?如果没有,改变顺序的理由是什么?它是确定性的,还是随机的?还是定义了实现 当我重复调用同一个python程序时(不是随机的,不是依赖输入的),我会得到相同的集合顺序吗是python';s";“设置”;马厩?,python,set,Python,Set,当回答另一个SO问题()时,问题出现了 当我在一个python集上迭代几次(在调用之间不改变它)时,我能假定它总是以相同的顺序返回元素吗?如果没有,改变顺序的理由是什么?它是确定性的,还是随机的?还是定义了实现 当我重复调用同一个python程序时(不是随机的,不是依赖输入的),我会得到相同的集合顺序吗 根本的问题是,python集合迭代顺序是否仅取决于用于实现集合的算法,还是取决于执行上下文?集合的定义是无序的、唯一的元素()。您应该只关心接口,而不关心实现。如果您想要一个有序的枚举,您可能应
根本的问题是,python集合迭代顺序是否仅取决于用于实现集合的算法,还是取决于执行上下文?集合的定义是无序的、唯一的元素()。您应该只关心接口,而不关心实现。如果您想要一个有序的枚举,您可能应该将其放入一个列表中并对其进行排序
Python有许多不同的实现。不要依赖于未记录的行为,因为您的代码可能会在不同的Python实现中中断 关于集合的稳定性没有正式的保证。但是,在CPython实现中,只要集合没有改变,项目将以相同的顺序生成。集合被实现为开放寻址哈希表(带有一个主探测),因此插入或删除项目可以完全改变顺序(特别是当触发调整大小时,它会重新组织项目在内存中的布局)。您也可以有两个相同的集合,但它们以不同的顺序生成项目,例如:
>>> s1 = {-1, -2}
>>> s2 = {-2, -1}
>>> s1 == s2
True
>>> list(s1), list(s2)
([-1, -2], [-2, -1])
除非您非常确定您拥有相同的集合,并且在两次迭代之间没有任何内容涉及到它,否则最好不要依赖它保持不变。例如,对中间调用的函数进行看似无关的更改可能会产生很难发现的bug。这肯定是实现定义的。政府只说 集合是无序集合,不记录元素位置或插入顺序
为什么不使用创建您自己的OrderedSet类呢?正如所指出的,这是一个严格的实现细节 但是,只要不改变调用之间的结构,就没有理由让只读操作(=迭代)随着时间而改变:任何正常的实现都不会这样做。即使是可用于实现集合(例如跳过列表)的随机(=非确定性)数据结构,在未发生更改时也不会更改读取顺序 因此,理性地说,你可以放心地依靠这种行为 (我知道某些GCs可能会在后台线程中重新排序内存,但即使是这种重新排序,在数据结构级别上也不会明显,除非出现错误。) 当我调用相同的python时 重复编程(非随机、非随机) 输入相关),我会得到同样的结果吗 订购电视机 经过快速的实验,我现在可以回答这部分问题了。使用以下代码:
class Foo(object) :
def __init__(self,val) :
self.val = val
def __repr__(self) :
return str(self.val)
x = set()
for y in range(500) :
x.add(Foo(y))
print list(x)[-10:]
我可以触发我在另一个问题中所问的行为。如果我重复运行此操作,则输出会发生变化,但不是每次运行都会发生变化。它似乎是“弱随机”的,因为它变化缓慢。这当然取决于实现,所以我应该说我正在雪豹上运行macports Python2.6。虽然程序将在长时间内输出相同的答案,但做一些影响系统熵池的事情(写入磁盘通常是有效的)有时会将其踢到不同的输出中
类Foo只是一个简单的int包装器,因为实验表明,这不会发生在int集上。我认为这个问题是由于缺少对象的
\uuuuu eq\uuuu
和\uuuu hash\uuuuu
成员造成的,尽管我非常想知道潜在的解释/避免方法。同样有用的方法是重现/重复“坏”运行。有人知道它使用什么种子,或者我如何设置种子吗?Aset
或frozenset
本质上是一个无序的集合。在内部,集合基于a,键的顺序取决于插入顺序和算法。在CPython(又称标准Python)中,小于机器字大小(32位或64位)的整数散列到自身,但文本字符串、字节
字符串和日期时间
对象散列到随机变化的整数;您可以通过设置pythonhasheed
环境变量来控制这一点
从\uuuu散列\uuuuu
文档:
注意
默认情况下,str
、字节
和日期时间
对象被不可预测的随机值“腌制”。虽然他们
在单个Python进程中保持不变,它们不是
可在重复调用Python之间预测
这旨在提供针对拒绝服务的保护
由精心选择的利用最坏情况的输入引起
dict插入的性能,O(n^2)复杂度。看见
详情请参阅
更改哈希值会影响dict、set和
其他映射。Python从未对这种排序做出过保证
(它通常在32位和64位构建之间变化)
另见蟒蛇种子
散列其他类的对象的结果取决于类的方法的细节
所有这一切的结果是,您可以有两个包含相同字符串的集合,但当您将它们转换为列表时,它们可以进行不相等的比较。或者他们可能不会下面的一些代码演示了这一点。在某些运行中,它将只是循环,不打印任何内容,但在其他运行中,它将快速找到使用与原始文件不同顺序的集合
from random import seed, shuffle
seed(42)
data = list('abcdefgh')
a = frozenset(data)
la = list(a)
print(''.join(la), a)
while True:
shuffle(data)
lb = list(frozenset(data))
if lb != la:
print(''.join(data), ''.join(lb))
break
典型输出
dachbgef frozenset({'d', 'a', 'c', 'h', 'b', 'g', 'e', 'f'})
deghcfab dahcbgef
答案是否定的。 Python集操作不稳定。 我做了一个简单的实验来证明这一点 Th
import random
random.seed(1)
x=[]
class aaa(object):
def __init__(self,a,b):
self.a=a
self.b=b
for i in range(5):
x.append(aaa(random.choice('asf'),random.randint(1,4000)))
for j in x:
print(j.a,j.b)
print('====')
for j in set(x):
print(j.a,j.b)
a 2332
a 1045
a 2030
s 1935
f 1555
====
a 2030
a 2332
f 1555
a 1045
s 1935
Process finished with exit code 0
a 2332
a 1045
a 2030
s 1935
f 1555
====
s 1935
a 2332
a 1045
f 1555
a 2030
Process finished with exit code 0