好的,我来晚了一点,但是我一直在思考这个问题,在查看Python(CPython)的实现代码后,我有一个我喜欢的解释。如果有人知道为什么它很傻或者错误,我希望能听到为什么。
问题是使用迭代器遍历列表,同时允许该列表发生更改。
所有迭代器需要做的就是告诉你在当前项之后(即使用next()函数)哪个项目在(在这种情况下)列表中。
我认为目前实现迭代器的方式是,它们只跟踪它们迭代过的最后一个元素的索引。在iterobject.c中查看可以看到似乎是迭代器的定义:
typedef struct {
PyObject_HEAD
Py_ssize_t it_index;
PyObject *it_seq;
} seqiterobject;
it_seq
指向正在迭代的序列,it_index
给出了迭代器提供的最后一项的索引。
当迭代器刚刚提供了第 n 个项目并从序列中删除该项目时,后续列表元素及其索引之间的对应关系会发生变化。前 (n+1) 个项目成为迭代器关注的第 n 个项目。换句话说,迭代器现在认为序列中的“下一个”项目实际上是“当前”项目。
因此,当要求提供下一个项目时,它将提供前 (n+2) 个项目(即新的 (n+1) 个项目)。
因此,对于所讨论的代码,迭代器的 next()
方法仅会从原始列表中提供 n+0、n+2、n+4 等元素。n+1、n+3、n+5 等项目永远不会暴露给 remove
语句。
尽管问题代码的预期活动很清晰(至少对于人来说),但迭代器要监视其迭代的序列中的更改,然后以“人类”方式采取行动可能需要更多的内省。
如果迭代器可以返回先前或当前序列的元素,则可能会有一般性解决方法,但由于现在的情况是,您需要迭代列表的副本,并确保在迭代器到达它们之前不删除任何项目。
letters = []
? :-) - paxdiablo