在Python中,如何确定可迭代对象具有稳定的迭代顺序?

4
在Python中,我如何确定可迭代对象是否具有稳定的迭代顺序?
有一个collections.Iterable抽象基类,但没有稳定的对应物。
我之所以问这个问题是为了能够防止用户在将迭代顺序不稳定的可迭代对象(例如dictset等)无意中传递给对迭代稳定性至关重要的函数时出错或者警告他们。

只是好奇,为什么稳定性很重要? - grieve
@grieve 传递回调函数列表是有意义的(顺序是明确定义的),但传递回调函数集合(顺序是随机的)可能是调用者的错误。 - Piotr Dobrogost
1个回答

7
你可能需要关注的一个东西是collections.Sequence。它比你想要的更为具体,因为根据文档,序列“支持使用整数索引高效访问元素”;但它又不够具体,因为没有明确保证两次获取相同索引一定会返回相同的值。但这足以区分列表和元组与字典和集合。
然而,在一般情况下是没有方法的。一般情况下也不能有方法,因为你可以编写任何你喜欢的可迭代对象,并且没有要求你指定它是否稳定。例如,你可以这样做:
>>> def f():
...     if random.random() < 0.5:
...         for a in xrange(10):
...             yield a
...     else:
...         stuff = range(10)
...         random.shuffle(stuff)
...         for a in stuff:
...             yield a
>>> list(f())
0: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(f())
1: [7, 0, 2, 8, 5, 1, 4, 3, 6, 9]

迭代器可以在不声明其是否稳定的情况下编写,而且通过迭代某些东西来告诉它是否会以后以相同的方式迭代是不可能的,这意味着没有办法确定给定迭代器是否稳定。 我建议您简单地记录函数需要迭代顺序的稳定性。 您还可以明确检查已知可能不稳定的内置类型,并在这些类型上引发错误。 但是,通常无法检查任意用户定义的迭代器的稳定性。

唯一能做的就是尝试检测不稳定性(例如,您之前看到过这个 ID,并且索引按不同顺序出现),然后进行断言,但这几乎没有什么意义。 - abarnert
“collections.Sequence”在这里没有用处,因为它要求除了可迭代性之外还必须使用整数索引来访问元素。我正在寻找通用解决方案,因为我想避免显式类型检查。但是我同意,如果语言没有提供一种声明迭代稳定性的方法,那么可能不可能实现。 - Piotr Dobrogost
1
@martineau:这是简化已知稳定可迭代类型(或已知不稳定可迭代类型)的识别过程的好主意,但它仍然无法帮助您确定任意可迭代对象是否稳定。 - BrenBarn
1
如链接答案中所述,代码的外部用户可以自行注册类,以便它们得到适当处理。我认为没有实际的方法来处理任意未知类。最好的做法可能是假设它不是,并发出警告建议用户注册传递的实例的类。 - martineau
@BrenBarn:在你的例子中,通过调用f()创建的两个list本身就是稳定可迭代的东西。 - martineau
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接