为什么我不能改变我正在迭代的集合?

时间:2016-07-17 15:43:05

标签: python

我已经看过建议的解决方案和解决方法,但无法找到选择的解释,不允许在迭代时更改集。 你能帮我理解为什么这没关系

In [1]: l = [1]

In [2]: for i in l:
            l.append(2*i)
            if len(l)>10:
                    break

In [3]: l
Out[3]: [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]

虽然这不行

In [4]: l = {1}

In [5]: for i in l:
            l.add(2*i)
            if len(l)>10:
                    break
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-5-b5bdff4a382b> in <module>()
----> 1 for i in l:
      2         l.add(2*i)
      3         if len(l)>10:
      4                 break
      5

RuntimeError: Set changed size during iteration

迭代时更改集合有什么不好?

我知道未定义集合中的顺序,因此next可能会遇到困难。这是什么原因?

3 个答案:

答案 0 :(得分:4)

一个集由哈希表支持(参见Why is the order in Python dictionaries and sets arbitrary?)。集合中的条目根据其哈希值插入到该表中,而哈希值又决定了它们的顺序。

在该哈希表中添加或删除项目将改变迭代顺序,有时可能会重新调整表格(根据新表格大小重新插入所有现有条目) 。因为这个迭代不能在集合被改变的那一刻继续;否则,您可能会再次看到相同的值,即使是以不同的顺序。

另一方面,

列表具有明确定义的顺序。插入或删除项目可以改变该顺序,但是以明确定义的方式。因此,列表迭代器可以使用不断增加的索引来查找“下一个”项,直到该索引与当前列表长度匹配。

答案 1 :(得分:0)

强制执行集合以允许在迭代时进行更改将限制它具有非常差的性能。考虑链表和指向节点的简单迭代器。想想扩展并需要重新分配内存的动态数组(哈希表,即dictset的实现,使用这样的数组。list用这样的数组实现)等等。

答案 2 :(得分:0)

首先,您需要了解how dicts workSets以相同的方式(在存储密钥方面)工作。我不认为我能比Brandon Rhodes at PyCon更好地解释这个问题(谈话在某个时候回答了这个问题,并且是dictssets背后的数据结构的现象参考

基本上对于dicts / sets,迭代次序可以随着项目的添加或删除而改变。 lists也是如此。