我按如下方式迭代列表:
some_list = [1, 2, 3, 4]
another_list = [1, 2, 3, 4]
for idx, item in enumerate(some_list):
del some_list[idx]
for item in another_list:
another_list.remove(item)
当我打印出列表的内容时
>>> some_list
[2, 4]
>>> another_list
[2, 4]
我知道Python不支持在迭代时修改list
,而正确的方法是迭代列表副本(所以请不要downvote)。但我想知道幕后究竟发生了什么,即为什么输出上面的代码段[2, 4]
?
答案 0 :(得分:8)
您可以使用自制的迭代器来显示迭代器的状态(在本例中为print
s):
class CustomIterator(object):
def __init__(self, seq):
self.seq = seq
self.idx = 0
def __iter__(self):
return self
def __next__(self):
print('give next element:', self.idx)
for idx, item in enumerate(self.seq):
if idx == self.idx:
print(idx, '--->', item)
else:
print(idx, ' ', item)
try:
nxtitem = self.seq[self.idx]
except IndexError:
raise StopIteration
self.idx += 1
return nxtitem
next = __next__ # py2 compat
然后在要检查的列表周围使用它:
some_list = [1, 2, 3, 4]
for idx, item in enumerate(CustomIterator(some_list)):
del some_list[idx]
这应该说明在这种情况下会发生什么:
give next element: 0
0 ---> 1
1 2
2 3
3 4
give next element: 1
0 2
1 ---> 3
2 4
give next element: 2
0 2
1 4
它仅适用于序列。它对于映射或集合来说更复杂。
答案 1 :(得分:1)
我想知道幕后究竟发生了什么
众所周知,列表中的每个项目都有自己独特的索引;从0开始按顺序排列。如果我们删除一个项目,那么索引大于我们删除的项目的任何项目现在都已向下移动。
这就是重要的原因:
foo = ['a', 'b', 'c', 'd']
for index in range(len(foo)):
del foo[index]
在这个循环中,我们删除了所有元素,因此我们最终应该使用foo == []
,对吧?不是这种情况。在我们第一次循环浏览时,我们删除索引0
处的项目,索引1
的项目成为索引0
的项目。我们下次循环时,会删除索引为1
的项目,该项目以前是索引2的项目。
在前两次迭代中,我们已从数组中删除了'a'
和'c'
,但我们忽略了删除'b'
。一旦我们进入第三次迭代(虽然我们删除索引2
),但不再是索引2
的元素;只有索引0
和1
。当我们尝试删除索引2
中不存在的项时,会引发异常,并且循环停止。结果是一个看似如下的错位数组:['a', 'd']
。